From 8cb05b5ab7e29ed067b1326bec9caf8274918126 Mon Sep 17 00:00:00 2001 From: Martin Fuchs Date: Mon, 31 Jul 2006 23:23:19 +0000 Subject: [PATCH] IBrowser: update XMLStorage library and remove Expat dependency svn path=/trunk/; revision=23398 --- .../base/applications/ibrowser/Makefile-MinGW | 3 +- .../applications/ibrowser/Makefile-precomp | 3 +- .../applications/ibrowser/expat-license.txt | 22 - .../base/applications/ibrowser/favorites.cpp | 12 +- .../base/applications/ibrowser/ibrowser.dsp | 6 +- .../applications/ibrowser/ibrowser.rbuild | 3 +- .../applications/ibrowser/make_ibrowser.dsp | 12 +- .../ibrowser/utility/xmlstorage.cpp | 653 ++++++---- .../ibrowser/utility/xmlstorage.h | 1147 ++++++++++++++--- .../ibrowser/utility/xs-native.cpp | 438 +++++++ 10 files changed, 1822 insertions(+), 477 deletions(-) delete mode 100644 reactos/base/applications/ibrowser/expat-license.txt create mode 100644 reactos/base/applications/ibrowser/utility/xs-native.cpp diff --git a/reactos/base/applications/ibrowser/Makefile-MinGW b/reactos/base/applications/ibrowser/Makefile-MinGW index cd1d90f5821..8d71521635c 100644 --- a/reactos/base/applications/ibrowser/Makefile-MinGW +++ b/reactos/base/applications/ibrowser/Makefile-MinGW @@ -50,13 +50,14 @@ OBJECTS = \ webchild.o \ mainframe.o \ favorites.o \ + xs-native.o \ xmlstorage.o LIBS = gdi32 comctl32 shell32 ole32 uuid oleaut32 all: $(TARGET) -$(TARGET): $(OBJECTS) $(PROGRAM)$(RES_SUFFIX) libexpat.dll +$(TARGET): $(OBJECTS) $(PROGRAM)$(RES_SUFFIX) $(LINK) $(LFLAGS) -o $@ $^ $(addprefix -l,$(LIBS)) $(addprefix -l,$(DELAYIMPORTS)) ibrowser$(RES_SUFFIX): $(PROGRAM)_intres.rc res/*.bmp res/*.ico diff --git a/reactos/base/applications/ibrowser/Makefile-precomp b/reactos/base/applications/ibrowser/Makefile-precomp index 08b7f253a4f..47b5f305501 100644 --- a/reactos/base/applications/ibrowser/Makefile-precomp +++ b/reactos/base/applications/ibrowser/Makefile-precomp @@ -52,6 +52,7 @@ OBJECTS = \ webchild.o \ mainframe.o \ favorites.o \ + xs-native.o \ xmlstorage.o LIBS = gdi32 comctl32 shell32 ole32 oleaut32 uuid @@ -61,7 +62,7 @@ all: precomp.h.gch $(TARGET) precomp.h.gch: *.h utility/*.h $(CXX) $(CFLAGS) precomp.h -$(TARGET): $(OBJECTS) $(PROGRAM)$(RES_SUFFIX) libexpat.dll +$(TARGET): $(OBJECTS) $(PROGRAM)$(RES_SUFFIX) $(LINK) $(LFLAGS) -o $@ $^ $(addprefix -l,$(LIBS)) $(addprefix -l,$(DELAYIMPORTS)) ibrowser$(RES_SUFFIX): $(PROGRAM)_intres.rc res/*.bmp res/*.ico diff --git a/reactos/base/applications/ibrowser/expat-license.txt b/reactos/base/applications/ibrowser/expat-license.txt deleted file mode 100644 index 5c5d524a1f8..00000000000 --- a/reactos/base/applications/ibrowser/expat-license.txt +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd - and Clark Cooper -Copyright (c) 2001, 2002, 2003 Expat maintainers. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/reactos/base/applications/ibrowser/favorites.cpp b/reactos/base/applications/ibrowser/favorites.cpp index 47f7948b688..60843a411ab 100644 --- a/reactos/base/applications/ibrowser/favorites.cpp +++ b/reactos/base/applications/ibrowser/favorites.cpp @@ -429,10 +429,10 @@ bool Favorites::read(LPCTSTR path) XMLDoc xbel; if (!xbel.read(path)) - if (xbel._last_error == XML_ERROR_NO_ELEMENTS) +/*@@ if (xbel._last_error == XML_ERROR_NO_ELEMENTS) return false; - else - MessageBox(0/*@@g_Globals._hwndDesktop*/, String(xbel._last_error_msg.c_str()), + else */ + MessageBox(0/*@@g_Globals._hwndDesktop*/, xbel._errors.str(), TEXT("ROS Explorer - reading bookmark file"), MB_OK); const_XMLPos pos(&xbel); @@ -457,9 +457,9 @@ void Favorites::write(LPCTSTR path) const super::write(pos); pos.back(); - xbel._header._doctype = ""; + xbel._format._doctype._name = "xbel"; + xbel._format._doctype._public = "//IDN python.org//DTD XML Bookmark Exchange Language 1.0//EN//XML"; + xbel._format._doctype._system = "http://www.python.org/topics/xml/dtds/xbel-1.0.dtd"; xbel.write(path); } diff --git a/reactos/base/applications/ibrowser/ibrowser.dsp b/reactos/base/applications/ibrowser/ibrowser.dsp index 902a9901ded..63164c07416 100644 --- a/reactos/base/applications/ibrowser/ibrowser.dsp +++ b/reactos/base/applications/ibrowser/ibrowser.dsp @@ -28,7 +28,7 @@ CFG=IBROWSER - WIN32 DEBUG # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" -CPP=cl.exe +CPP=cl.cmd RSC=rc.exe !IF "$(CFG)" == "ibrowser - Win32 Release" @@ -199,6 +199,10 @@ SOURCE=.\utility\xmlstorage.cpp SOURCE=.\utility\xmlstorage.h # End Source File +# Begin Source File + +SOURCE=".\utility\xs-native.cpp" +# End Source File # End Group # Begin Group "resources" diff --git a/reactos/base/applications/ibrowser/ibrowser.rbuild b/reactos/base/applications/ibrowser/ibrowser.rbuild index a90eb16fad6..c5fb6d3354a 100644 --- a/reactos/base/applications/ibrowser/ibrowser.rbuild +++ b/reactos/base/applications/ibrowser/ibrowser.rbuild @@ -3,7 +3,6 @@ -fexceptions . - include/expat @@ -18,12 +17,12 @@ ole32 oleaut32 shell32 - expat precomp.h utility.cpp window.cpp xmlstorage.cpp + xs-native.cpp ibrowser.cpp favorites.cpp diff --git a/reactos/base/applications/ibrowser/make_ibrowser.dsp b/reactos/base/applications/ibrowser/make_ibrowser.dsp index 64850314d87..3e1e61b0f7b 100644 --- a/reactos/base/applications/ibrowser/make_ibrowser.dsp +++ b/reactos/base/applications/ibrowser/make_ibrowser.dsp @@ -4,7 +4,7 @@ # TARGTYPE "Win32 (x86) External Target" 0x0106 -CFG=make_ibrowser - Win32 bjam +CFG=make_ibrowser - Win32 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE @@ -13,7 +13,7 @@ CFG=make_ibrowser - Win32 bjam !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE -!MESSAGE NMAKE /f "make_ibrowser.mak" CFG="make_ibrowser - Win32 bjam" +!MESSAGE NMAKE /f "make_ibrowser.mak" CFG="make_ibrowser - Win32 Release" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE @@ -43,7 +43,7 @@ CFG=make_ibrowser - Win32 bjam # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" -# PROP Cmd_Line "msdevfilt -gcc -pipe "perl d:\tools\gSTLFilt.pl" make -f Makefile-precomp UNICODE=0" +# PROP Cmd_Line "msdevfilt -gcc -pipe "perl d:\tools\gSTLFilt.pl" mingw32-make -f Makefile-precomp UNICODE=0" # PROP Rebuild_Opt "clean all" # PROP Target_File "ibrowser.exe" # PROP Bsc_Name "" @@ -64,7 +64,7 @@ CFG=make_ibrowser - Win32 bjam # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" -# PROP Cmd_Line "msdevfilt -gcc -pipe "perl d:\tools\gSTLFilt.pl" make -f Makefile-precomp UNICODE=0 DEBUG=1" +# PROP Cmd_Line "msdevfilt -gcc -pipe "perl d:\tools\gSTLFilt.pl" mingw32-make -f Makefile-precomp UNICODE=0 DEBUG=1" # PROP Rebuild_Opt "clean all" # PROP Target_File "ibrowser.exe" # PROP Bsc_Name "msdevfilt -gcc -pipe "perl d:\tools\gSTLFilt.pl" make -f Makefile.MinGW UNICODE=0 DEBUG=1" @@ -85,7 +85,7 @@ CFG=make_ibrowser - Win32 bjam # PROP Use_Debug_Libraries 1 # PROP Output_Dir "UDebug" # PROP Intermediate_Dir "UDebug" -# PROP Cmd_Line "msdevfilt -gcc -pipe "perl d:\tools\gSTLFilt.pl" make -f Makefile.MinGW UNICODE=1 DEBUG=1" +# PROP Cmd_Line "msdevfilt -gcc -pipe "perl d:\tools\gSTLFilt.pl" mingw32-make -f Makefile.MinGW UNICODE=1 DEBUG=1" # PROP Rebuild_Opt "clean all" # PROP Target_File "ibrowser.exe" # PROP Bsc_Name "" @@ -106,7 +106,7 @@ CFG=make_ibrowser - Win32 bjam # PROP Use_Debug_Libraries 0 # PROP Output_Dir "URelease" # PROP Intermediate_Dir "URelease" -# PROP Cmd_Line "msdevfilt -gcc make -f Makefile-precomp UNICODE=1" +# PROP Cmd_Line "msdevfilt -gcc mingw32-make -f Makefile-precomp UNICODE=1" # PROP Rebuild_Opt "clean all" # PROP Target_File "ibrowser.exe" # PROP Bsc_Name "" diff --git a/reactos/base/applications/ibrowser/utility/xmlstorage.cpp b/reactos/base/applications/ibrowser/utility/xmlstorage.cpp index 0a2dc79d8a7..7ebfdae8b89 100644 --- a/reactos/base/applications/ibrowser/utility/xmlstorage.cpp +++ b/reactos/base/applications/ibrowser/utility/xmlstorage.cpp @@ -4,7 +4,7 @@ // // xmlstorage.cpp // - // Copyright (c) 2004, 2005 Martin Fuchs + // Copyright (c) 2004, 2005, 2006 Martin Fuchs // @@ -36,22 +36,29 @@ */ +#ifndef XS_NO_COMMENT +#define XS_NO_COMMENT // no #pragma comment(lib, ...) statements in .lib files +#endif + //#include "xmlstorage.h" #include // work around GCC's wide string constant bug #ifdef __GNUC__ -const LPCXSSTR XMLStorage::XS_TRUE = XS_TEXT("true"); -const LPCXSSTR XMLStorage::XS_FALSE = XS_TEXT("false"); -const LPCXSSTR XMLStorage::XS_NUMBERFMT = XS_TEXT("%d"); +const LPCXSSTR XMLStorage::XS_EMPTY = XS_EMPTY_STR; +const LPCXSSTR XMLStorage::XS_TRUE = XS_TRUE_STR; +const LPCXSSTR XMLStorage::XS_FALSE = XS_FALSE_STR; +const LPCXSSTR XMLStorage::XS_INTFMT = XS_INTFMT_STR; +const LPCXSSTR XMLStorage::XS_FLOATFMT = XS_FLOATFMT_STR; #endif namespace XMLStorage { -static std::string unescape(const char* s, char b='"', char e='"') + /// remove escape characters from zero terminated string +static std::string unescape(const char* s, char b, char e) { const char* end = s + strlen(s); @@ -68,7 +75,13 @@ static std::string unescape(const char* s, char b='"', char e='"') return std::string(s, end-s); } -static std::string unescape(const char* s, int l, char b='"', char e='"') +inline std::string unescape(const char* s) +{ + return unescape(s, '"', '"'); +} + + /// remove escape characters from string with specified length +static std::string unescape(const char* s, size_t l, char b, char e) { const char* end = s + l; @@ -85,6 +98,11 @@ static std::string unescape(const char* s, int l, char b='"', char e='"') return std::string(s, end-s); } +inline std::string unescape(const char* s, size_t l) +{ + return unescape(s, l, '"', '"'); +} + /// move XPath like to position in XML tree bool XMLPos::go(const char* path) @@ -137,7 +155,7 @@ const XMLNode* XMLNode::find_relative(const char* path) const if (slash == path) return NULL; - int l = slash? slash-path: strlen(path); + size_t l = slash? slash-path: strlen(path); std::string comp(path, l); path += l; @@ -198,7 +216,7 @@ XMLNode* XMLNode::create_relative(const char* path) if (slash == path) return NULL; - int l = slash? slash-path: strlen(path); + size_t l = slash? slash-path: strlen(path); std::string comp(path, l); path += l; @@ -259,239 +277,113 @@ XMLNode* XMLNode::create_relative(const char* path) } - /// read XML stream into XML tree below _pos -XML_Status XMLReaderBase::read() -{ - XML_Status status = XML_STATUS_OK; - - while(status == XML_STATUS_OK) { - char* buffer = (char*) XML_GetBuffer(_parser, BUFFER_LEN); - - int l = read_buffer(buffer, BUFFER_LEN); - if (l < 0) - break; - - status = XML_ParseBuffer(_parser, l, false); - } - - if (status != XML_STATUS_ERROR) - status = XML_ParseBuffer(_parser, 0, true); - - if (_pos->_children.empty()) - _pos->_trailing.append(_content); - else - _pos->_children.back()->_trailing.append(_content); - - _content.erase(); - - return status; -} - - - /// store XML version and encoding into XML reader -void XMLCALL XMLReaderBase::XML_XmlDeclHandler(void* userData, const XML_Char* version, const XML_Char* encoding, int standalone) -{ - XMLReaderBase* pReader = (XMLReaderBase*) userData; - - if (version) - pReader->_xml_version = version; - - if (encoding) - pReader->_encoding = encoding; -} - - /// notifications about XML start tag -void XMLCALL XMLReaderBase::XML_StartElementHandler(void* userData, const XML_Char* name, const XML_Char** atts) -{ - XMLReaderBase* pReader = (XMLReaderBase*) userData; - XMLPos& pos = pReader->_pos; - - // search for end of first line - const char* s = pReader->_content.c_str(); - const char* p = s; - const char* e = p + pReader->_content.length(); - - for(; p_children.empty()) { // no children in last node? - if (pReader->_last_tag == TAG_START) - pos->_content.append(s, p-s); - else if (pReader->_last_tag == TAG_END) - pos->_trailing.append(s, p-s); - // else TAG_NONE -> don't store white space in root node - } else - pos->_children.back()->_trailing.append(s, p-s); - - std::string leading; - - if (p != e) - leading.assign(p, e-p); - - XMLNode* node = new XMLNode(String_from_XML_Char(name), leading); - - pos.add_down(node); - - while(*atts) { - const XML_Char* attr_name = *atts++; - const XML_Char* attr_value = *atts++; - - (*node)[String_from_XML_Char(attr_name)] = String_from_XML_Char(attr_value); - } - - pReader->_last_tag = TAG_START; - pReader->_content.erase(); -} - - /// notifications about XML end tag -void XMLCALL XMLReaderBase::XML_EndElementHandler(void* userData, const XML_Char* name) -{ - XMLReaderBase* pReader = (XMLReaderBase*) userData; - XMLPos& pos = pReader->_pos; - - // search for end of first line - const char* s = pReader->_content.c_str(); - const char* p = s; - const char* e = p + pReader->_content.length(); - - for(; p_children.empty()) // no children in current node? - pos->_content.append(s, p-s); - else - if (pReader->_last_tag == TAG_START) - pos->_content.append(s, p-s); - else - pos->_children.back()->_trailing.append(s, p-s); - - if (p != e) - pos->_end_leading.assign(p, e-p); - - pos.back(); - - pReader->_last_tag = TAG_END; - pReader->_content.erase(); -} - - /// store content, white space and comments -void XMLCALL XMLReaderBase::XML_DefaultHandler(void* userData, const XML_Char* s, int len) -{ - XMLReaderBase* pReader = (XMLReaderBase*) userData; - - pReader->_content.append(s, len); -} - - -std::string XMLReaderBase::get_error_string() const -{ - XML_Error error = XML_GetErrorCode(_parser); - - switch(error) { - case XML_ERROR_NONE: return "XML_ERROR_NONE"; - case XML_ERROR_NO_MEMORY: return "XML_ERROR_NO_MEMORY"; - case XML_ERROR_SYNTAX: return "XML_ERROR_SYNTAX"; - case XML_ERROR_NO_ELEMENTS: return "XML_ERROR_NO_ELEMENTS"; - case XML_ERROR_INVALID_TOKEN: return "XML_ERROR_INVALID_TOKEN"; - case XML_ERROR_UNCLOSED_TOKEN: return "XML_ERROR_UNCLOSED_TOKEN"; - case XML_ERROR_PARTIAL_CHAR: return "XML_ERROR_PARTIAL_CHAR"; - case XML_ERROR_TAG_MISMATCH: return "XML_ERROR_TAG_MISMATCH"; - case XML_ERROR_DUPLICATE_ATTRIBUTE: return "XML_ERROR_DUPLICATE_ATTRIBUTE"; - case XML_ERROR_JUNK_AFTER_DOC_ELEMENT: return "XML_ERROR_JUNK_AFTER_DOC_ELEMENT"; - case XML_ERROR_PARAM_ENTITY_REF: return "XML_ERROR_PARAM_ENTITY_REF"; - case XML_ERROR_UNDEFINED_ENTITY: return "XML_ERROR_UNDEFINED_ENTITY"; - case XML_ERROR_RECURSIVE_ENTITY_REF: return "XML_ERROR_RECURSIVE_ENTITY_REF"; - case XML_ERROR_ASYNC_ENTITY: return "XML_ERROR_ASYNC_ENTITY"; - case XML_ERROR_BAD_CHAR_REF: return "XML_ERROR_BAD_CHAR_REF"; - case XML_ERROR_BINARY_ENTITY_REF: return "XML_ERROR_BINARY_ENTITY_REF"; - case XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF: return "XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF"; - case XML_ERROR_MISPLACED_XML_PI: return "XML_ERROR_MISPLACED_XML_PI"; - case XML_ERROR_UNKNOWN_ENCODING: return "XML_ERROR_UNKNOWN_ENCODING"; - case XML_ERROR_INCORRECT_ENCODING: return "XML_ERROR_INCORRECT_ENCODING"; - case XML_ERROR_UNCLOSED_CDATA_SECTION: return "XML_ERROR_UNCLOSED_CDATA_SECTION"; - case XML_ERROR_EXTERNAL_ENTITY_HANDLING: return "XML_ERROR_EXTERNAL_ENTITY_HANDLING"; - case XML_ERROR_NOT_STANDALONE: return "XML_ERROR_NOT_STANDALONE"; - case XML_ERROR_UNEXPECTED_STATE: return "XML_ERROR_UNEXPECTED_STATE"; - case XML_ERROR_ENTITY_DECLARED_IN_PE: return "XML_ERROR_ENTITY_DECLARED_IN_PE"; - case XML_ERROR_FEATURE_REQUIRES_XML_DTD: return "XML_ERROR_FEATURE_REQUIRES_XML_DTD"; - case XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING: return "XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING"; - case XML_ERROR_UNBOUND_PREFIX: return "XML_ERROR_UNBOUND_PREFIX"; - // EXPAT version >= 1.95.8 -#if XML_MAJOR_VERSION>1 || (XML_MAJOR_VERSION==1 && XML_MINOR_VERSION>95) || (XML_MAJOR_VERSION==1 && XML_MINOR_VERSION==95 && XML_MICRO_VERSION>7) - case XML_ERROR_UNDECLARING_PREFIX: return "XML_ERROR_UNDECLARING_PREFIX"; - case XML_ERROR_INCOMPLETE_PE: return "XML_ERROR_INCOMPLETE_PE"; - case XML_ERROR_XML_DECL: return "XML_ERROR_XML_DECL"; - case XML_ERROR_TEXT_DECL: return "XML_ERROR_TEXT_DECL"; - case XML_ERROR_PUBLICID: return "XML_ERROR_PUBLICID"; - case XML_ERROR_SUSPENDED: return "XML_ERROR_SUSPENDED"; - case XML_ERROR_NOT_SUSPENDED: return "XML_ERROR_NOT_SUSPENDED"; - case XML_ERROR_ABORTED: return "XML_ERROR_ABORTED"; - case XML_ERROR_FINISHED: return "XML_ERROR_FINISHED"; - case XML_ERROR_SUSPEND_PE: return "XML_ERROR_SUSPEND_PE"; -//#endif -//#if XML_MAJOR_VERSION>=2 - /* Added in 2.0. */ - case XML_ERROR_RESERVED_PREFIX_XML: return "XML_ERROR_RESERVED_PREFIX_XML"; - case XML_ERROR_RESERVED_PREFIX_XMLNS: return "XML_ERROR_RESERVED_PREFIX_XMLNS"; - case XML_ERROR_RESERVED_NAMESPACE_URI: return "XML_ERROR_RESERVED_NAMESPACE_URI"; -#endif - } - - std::ostringstream out; - - out << "XML parser error #" << error; - - return out.str(); -} - - + /// encode XML string literals std::string EncodeXMLString(const XS_String& str) { LPCXSSTR s = str.c_str(); - LPXSSTR buffer = (LPXSSTR)alloca(5*sizeof(XS_CHAR)*XS_len(s)); // worst case. "&" - LPXSSTR o = buffer; + size_t l = XS_len(s); - for(LPCXSSTR p=s; *p; ++p) - switch(*p) { - case '&': - *o++ = '&'; *o++ = 'a'; *o++ = 'm'; *o++ = 'p'; *o++ = ';'; - break; + if (l <= BUFFER_LEN) { + LPXSSTR buffer = (LPXSSTR)alloca(6*sizeof(XS_CHAR)*XS_len(s)); // worst case """ / "'" + LPXSSTR o = buffer; - case '<': - *o++ = '&'; *o++ = 'l'; *o++ = 't'; *o++ = ';'; - break; + for(LPCXSSTR p=s; *p; ++p) + switch(*p) { + case '&': + *o++ = '&'; *o++ = 'a'; *o++ = 'm'; *o++ = 'p'; *o++ = ';'; + break; - case '>': - *o++ = '&'; *o++ = 'g'; *o++ = 't'; *o++ = ';'; - break; + case '<': + *o++ = '&'; *o++ = 'l'; *o++ = 't'; *o++ = ';'; + break; - case '"': - *o++ = '&'; *o++ = 'q'; *o++ = 'u'; *o++ = 'o'; *o++ = 't'; *o++ = ';'; - break; + case '>': + *o++ = '&'; *o++ = 'g'; *o++ = 't'; *o++ = ';'; + break; - case '\'': - *o++ = '&'; *o++ = 'a'; *o++ = 'p'; *o++ = 'o'; *o++ = 's'; *o++ = ';'; - break; + case '"': + *o++ = '&'; *o++ = 'q'; *o++ = 'u'; *o++ = 'o'; *o++ = 't'; *o++ = ';'; + break; - default: - *o++ = *p; - } + case '\'': + *o++ = '&'; *o++ = 'a'; *o++ = 'p'; *o++ = 'o'; *o++ = 's'; *o++ = ';'; + break; + + default: + if ((unsigned)*p<20 && *p!='\t' && *p!='\r' && *p!='\n') { + char b[16]; + sprintf(b, "&%d;", (unsigned)*p); + for(const char*q=b; *q; ) + *o++ = *q++; + } else + *o++ = *p; + } #ifdef XS_STRING_UTF8 - return XS_String(buffer, o-buffer); + return XS_String(buffer, o-buffer); #else - return get_utf8(buffer, o-buffer); + return get_utf8(buffer, o-buffer); #endif + } else { // l > BUFFER_LEN + // encode the whole string in a CDATA section + std::string ret = ""; + + return ret; + +/* alternative code using ostringstream (beware: quite slow) +#include + + std::ostringstream out; + + LPCXSSTR s = str.c_str(); + + for(LPCXSSTR p=s; *p; ++p) + switch(*p) { + case '&': + out << "&"; + break; + + case '<': + out << "<"; + break; + + case '>': + out << ">"; + break; + + case '"': + out << """; + break; + + case '\'': + out << "'"; + break; + + default: + if ((unsigned)*p<20 && *p!='\t' *p!='\r' && *p!='\n') + out << "&" << (unsigned)*p << ";"; + else + out << *p; + } + +#ifdef XS_STRING_UTF8 + return XS_String(out.str()); +#else + return get_utf8(out.str()); +#endif + */ + } } + /// decode XML string literals XS_String DecodeXMLString(const XS_String& str) { LPCXSSTR s = str.c_str(); @@ -517,6 +409,16 @@ XS_String DecodeXMLString(const XS_String& str) p += 5; } else *o++ = *p; + } else if (*p=='<' && !XS_nicmp(p+1,XS_TEXT("!CDATA["),7)) { + p += 9; + LPCXSSTR e = XS_strstr(p, XS_TEXT("]]>")); + if (e) { + size_t l = e - p; + memcpy(o, p, l); + o += l; + p += 3; + } else + *o++ = *p; } else *o++ = *p; @@ -546,8 +448,28 @@ void XMLNode::write_worker(std::ostream& out, int indent) const } + /// print node without any white space +void XMLNode::plain_write_worker(std::ostream& out) const +{ + out << '<' << EncodeXMLString(*this); + + for(AttributeMap::const_iterator it=_attributes.begin(); it!=_attributes.end(); ++it) + out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\""; + + if (!_children.empty()/*@@ || !_content.empty()*/) { + out << ">"; + + for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it) + (*it)->plain_write_worker(out); + + out << ""; + } else + out << "/>"; +} + + /// pretty print node with children tree to output stream -void XMLNode::pretty_write_worker(std::ostream& out, int indent) const +void XMLNode::pretty_write_worker(std::ostream& out, const XMLFormat& format, int indent) const { for(int i=indent; i--; ) out << XML_INDENT_SPACE; @@ -557,23 +479,23 @@ void XMLNode::pretty_write_worker(std::ostream& out, int indent) const for(AttributeMap::const_iterator it=_attributes.begin(); it!=_attributes.end(); ++it) out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\""; - if (!_children.empty() || !_content.empty()) { - out << ">\n"; + if (!_children.empty()/*@@ || !_content.empty()*/) { + out << '>' << format._endl; for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it) - (*it)->pretty_write_worker(out, indent+1); + (*it)->pretty_write_worker(out, format, indent+1); for(int i=indent; i--; ) out << XML_INDENT_SPACE; - out << "\n"; + out << "' << format._endl; } else - out << "/>\n"; + out << "/>" << format._endl; } /// write node with children tree to output stream using smart formating -void XMLNode::smart_write_worker(std::ostream& out, int indent) const +void XMLNode::smart_write_worker(std::ostream& out, const XMLFormat& format, int indent) const { if (_leading.empty()) for(int i=indent; i--; ) @@ -592,7 +514,7 @@ void XMLNode::smart_write_worker(std::ostream& out, int indent) const out << '>'; if (_content.empty()) - out << '\n'; + out << format._endl; else out << _content; @@ -600,7 +522,7 @@ void XMLNode::smart_write_worker(std::ostream& out, int indent) const if (it != _children.end()) { for(; it!=_children.end(); ++it) - (*it)->smart_write_worker(out, indent+1); + (*it)->smart_write_worker(out, format, indent+1); if (_end_leading.empty()) for(int i=indent; i--; ) @@ -614,10 +536,269 @@ void XMLNode::smart_write_worker(std::ostream& out, int indent) const } if (_trailing.empty()) - out << '\n'; + out << format._endl; else out << _trailing; } +std::ostream& operator<<(std::ostream& out, const XMLError& err) +{ + out << err._systemId << "(" << err._line << ") [column " << err._column << "] : " + << err._message; + + return out; +} + + +void DocType::parse(const char* p) +{ + while(isspace((unsigned char)*p)) ++p; + + const char* start = p; + while(isxmlsym(*p)) ++p; + _name.assign(start, p-start); + + while(isspace((unsigned char)*p)) ++p; + + start = p; + while(isxmlsym(*p)) ++p; + std::string keyword(p, p-start); // "PUBLIC" or "SYSTEM" + + while(isspace((unsigned char)*p)) ++p; + + if (*p=='"' || *p=='\'') { + char delim = *p; + + start = ++p; + while(*p && *p!=delim) ++p; + + if (*p == delim) + _public.assign(start, p++-start); + } else + _public.erase(); + + while(isspace((unsigned char)*p)) ++p; + + if (*p=='"' || *p=='\'') { + char delim = *p; + + start = ++p; + while(*p && *p!=delim) ++p; + + if (*p == delim) + _system.assign(start, p++-start); + } else + _system.erase(); +} + + + +void XMLFormat::print_header(std::ostream& out, bool lf) const +{ + out << ""; + + if (lf) + out << _endl; + + if (!_doctype.empty()) { + out << ""; + + if (lf) + out << _endl; + } + + for(StyleSheetList::const_iterator it=_stylesheets.begin(); it!=_stylesheets.end(); ++it) { + it->print(out); + + if (lf) + out << _endl; + } + +/* if (!_additional.empty()) { + out << _additional; + + if (lf) + out << _endl; + } */ +} + +void StyleSheet::print(std::ostream& out) const +{ + out << ""; +} + + + /// return formated error message +std::string XMLError::str() const +{ + std::ostringstream out; + + out << *this; + + return out.str(); +} + + + /// return merged error strings +XS_String XMLErrorList::str() const +{ + std::ostringstream out; + + for(const_iterator it=begin(); it!=end(); ++it) + out << *it << std::endl; + + return out.str(); +} + + +void XMLReaderBase::finish_read() +{ + if (_pos->_children.empty()) + _pos->_trailing.append(_content); + else + _pos->_children.back()->_trailing.append(_content); + + _content.erase(); +} + + + /// store XML version and encoding into XML reader +void XMLReaderBase::XmlDeclHandler(const char* version, const char* encoding, int standalone) +{ + if (version) + _format._version = version; + + if (encoding) + _format._encoding = encoding; + + _format._standalone = standalone; +} + + + /// notifications about XML start tag +void XMLReaderBase::StartElementHandler(const XS_String& name, const XMLNode::AttributeMap& attributes) +{ + // search for end of first line + const char* s = _content.c_str(); + const char* p = s; + const char* e = p + _content.length(); + + for(; p_children.empty()) { // no children in last node? + if (_last_tag == TAG_START) + _pos->_content.append(s, p-s); + else if (_last_tag == TAG_END) + _pos->_trailing.append(s, p-s); + else // TAG_NONE at root node + p = s; + } else + _pos->_children.back()->_trailing.append(s, p-s); + + std::string leading; + + if (p != e) + leading.assign(p, e-p); + + XMLNode* node = new XMLNode(name, leading); + + _pos.add_down(node); + +#ifdef XMLNODE_LOCATION + node->_location = get_location(); +#endif + + node->_attributes = attributes; + + _last_tag = TAG_START; + _content.erase(); +} + + /// notifications about XML end tag +void XMLReaderBase::EndElementHandler() +{ + // search for end of first line + const char* s = _content.c_str(); + const char* p = s; + const char* e = p + _content.length(); + + for(; p_children.empty()) // no children in current node? + _pos->_content.append(s, p-s); + else + if (_last_tag == TAG_START) + _pos->_content.append(s, p-s); + else + _pos->_children.back()->_trailing.append(s, p-s); + + if (p != e) + _pos->_end_leading.assign(p, e-p); + + _pos.back(); + + _last_tag = TAG_END; + _content.erase(); +} + +#if defined(XS_USE_XERCES) || defined(XS_USE_EXPAT) + /// store content, white space and comments +void XMLReaderBase::DefaultHandler(const XML_Char* s, int len) +{ +#if defined(XML_UNICODE) || defined(XS_USE_XERCES) + _content.append(String_from_XML_Char(s, len)); +#else + _content.append(s, len); +#endif +} +#endif + + +XS_String XMLWriter::s_empty_attr; + + } // namespace XMLStorage diff --git a/reactos/base/applications/ibrowser/utility/xmlstorage.h b/reactos/base/applications/ibrowser/utility/xmlstorage.h index f3ef5cf781d..0eadea679b1 100644 --- a/reactos/base/applications/ibrowser/utility/xmlstorage.h +++ b/reactos/base/applications/ibrowser/utility/xmlstorage.h @@ -4,7 +4,7 @@ // // xmlstorage.h // - // Copyright (c) 2004, 2005 Martin Fuchs + // Copyright (c) 2004, 2005, 2006 Martin Fuchs // @@ -38,19 +38,107 @@ #ifndef _XMLSTORAGE_H + +#if _MSC_VER>=1400 +#ifndef _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES +#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 +#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT 1 +#define _CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES 1 +#endif +#endif + + +#ifdef XS_USE_XERCES + +#ifndef UNICODE +#ifndef XS_STRING_UTF8 +#define XS_STRING_UTF8 +#endif +#endif + +#include +#include + +using XERCES_CPP_NAMESPACE_QUALIFIER Locator; +using XERCES_CPP_NAMESPACE_QUALIFIER SAXParser; +using XERCES_CPP_NAMESPACE_QUALIFIER HandlerBase; +using XERCES_CPP_NAMESPACE_QUALIFIER InputSource; +using XERCES_CPP_NAMESPACE_QUALIFIER AttributeList; +using XERCES_CPP_NAMESPACE_QUALIFIER SAXParseException; + +typedef XMLCh XML_Char; + +#elif defined(XS_USE_EXPAT) + #include -#ifdef _MSC_VER -#pragma comment(lib, "libexpat.lib") -#pragma warning(disable: 4786) #endif -#include // for LPCTSTR +#ifdef _MSC_VER +#pragma warning(disable: 4786) + +#ifndef XS_NO_COMMENT + +#ifdef XS_USE_XERCES +#ifdef _DEBUG +#pragma comment(lib, "xerces-c_2D") +#else +#pragma comment(lib, "xerces-c_2") +#endif +#elif defined(XS_USE_EXPAT) +#ifdef XML_STATIC +#ifndef _DEBUG +#pragma comment(lib, "libexpatMT") +#endif +#else +#pragma comment(lib, "libexpat") +#endif +#endif + +#ifndef _STRING_DEFINED // _STRING_DEFINED only allowed if using xmlstorage.cpp embedded in the project +#if defined(_DEBUG) && defined(_DLL) // DEBUG version only supported with MSVCRTD +#if _MSC_VER==1400 +#pragma comment(lib, "xmlstorage-vc8d") +#else +#pragma comment(lib, "xmlstorage-vc6d") +#endif +#else +#ifdef _DLL +#if _MSC_VER==1400 +#pragma comment(lib, "xmlstorage-vc8") +#else +#pragma comment(lib, "xmlstorage-vc6") +#endif +#elif defined(_MT) +#if _MSC_VER==1400 +#pragma comment(lib, "xmlstorage-vc8t") +#else +#pragma comment(lib, "xmlstorage-vc6t") +#endif +#else + // -ML is no more supported by VS2005. +#pragma comment(lib, "xmlstorage-vc6l") +#endif +#endif +#endif // _STRING_DEFINED + +#endif // XS_NO_COMMENT + +#endif // _MSC_VER + #ifdef UNICODE +#ifndef _UNICODE #define _UNICODE #endif +#else +#ifdef _UNICODE +#define UNICODE +#endif +#endif + +#include // for LPCTSTR #include #include @@ -78,25 +166,48 @@ namespace XMLStorage { #define XS_TEXT(x) x #define LPXSSTR LPSTR #define LPCXSSTR LPCSTR +#define XS_cmp strcmp #define XS_icmp stricmp +#define XS_ncmp strncmp #define XS_nicmp strnicmp #define XS_toi atoi +#define XS_tod strtod #define XS_len strlen -#define XS_sprintf sprintf -#define XS_vsprintf vsprintf +#define XS_snprintf _snprintf +#define XS_vsnprintf _vsnprintf +#define XS_strstr strstr #else #define XS_CHAR TCHAR #define XS_TEXT(x) TEXT(x) #define LPXSSTR LPTSTR #define LPCXSSTR LPCTSTR +#define XS_cmp _tcscmp #define XS_icmp _tcsicmp +#define XS_ncmp _tcsncmp #define XS_nicmp _tcsnicmp #define XS_toi _ttoi +#define XS_tod _tcstod #define XS_len _tcslen -#define XS_sprintf _stprintf -#define XS_vsprintf _vstprintf +#define XS_snprintf _sntprintf +#define XS_vsnprintf _vsntprintf +#define XS_strstr _tcsstr #endif +#ifndef COUNTOF +#if _MSC_VER>=1400 +#define COUNTOF _countof +#else +#define COUNTOF(b) (sizeof(b)/sizeof(b[0])) +#endif +#endif + + +int inline isxmlsym(unsigned char c) +{ + return isalnum(c) || c=='_' || c=='-'; +} + + #if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8) #define XS_String String @@ -121,46 +232,46 @@ struct XS_String XS_String() {} XS_String(LPCXSSTR s) {if (s) super::assign(s);} - XS_String(LPCXSSTR s, int l) : super(s, l) {} + XS_String(LPCXSSTR s, size_t l) : super(s, l) {} XS_String(const super& other) : super(other) {} XS_String(const XS_String& other) : super(other) {} #if defined(UNICODE) && !defined(XS_STRING_UTF8) XS_String(LPCSTR s) {assign(s);} - XS_String(LPCSTR s, int l) {assign(s, l);} + XS_String(LPCSTR s, size_t l) {assign(s, l);} XS_String(const std::string& other) {assign(other.c_str());} XS_String& operator=(LPCSTR s) {assign(s); return *this;} - void assign(LPCSTR s) {if (s) {int bl=strlen(s); LPWSTR b=(LPWSTR)alloca(sizeof(WCHAR)*bl); super::assign(b, MultiByteToWideChar(CP_ACP, 0, s, bl, b, bl));} else erase();} - void assign(LPCSTR s, int l) {if (s) {int bl=l; LPWSTR b=(LPWSTR)alloca(sizeof(WCHAR)*bl); super::assign(b, MultiByteToWideChar(CP_ACP, 0, s, l, b, bl));} else erase();} + 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();} + 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();} #else XS_String(LPCWSTR s) {assign(s);} - XS_String(LPCWSTR s, int l) {assign(s, l);} + XS_String(LPCWSTR s, size_t l) {assign(s, l);} XS_String(const std::wstring& other) {assign(other.c_str());} XS_String& operator=(LPCWSTR s) {assign(s); return *this;} #ifdef XS_STRING_UTF8 void assign(const XS_String& s) {assign(s.c_str());} - void assign(LPCWSTR s) {if (s) {int bl=wcslen(s); LPSTR b=(LPSTR)alloca(bl); super::assign(b, WideCharToMultiByte(CP_UTF8, 0, s, bl, b, bl, 0, 0));} else erase();} - void assign(LPCWSTR s, int l) {int bl=l; if (s) {LPSTR b=(LPSTR)alloca(bl); super::assign(b, WideCharToMultiByte(CP_UTF8, 0, s, l, b, bl, 0, 0));} else erase();} + 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();} + 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();} #else // if !UNICODE && !XS_STRING_UTF8 - void assign(LPCWSTR s) {if (s) {int bl=wcslen(s); LPSTR b=(LPSTR)alloca(bl); super::assign(b, WideCharToMultiByte(CP_ACP, 0, s, bl, b, bl, 0, 0));} else erase();} - void assign(LPCWSTR s, int l) {int bl=l; if (s) {LPSTR b=(LPSTR)alloca(bl); super::assign(b, WideCharToMultiByte(CP_ACP, 0, s, l, b, bl, 0, 0));} else erase();} + 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();} + 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();} #endif #endif XS_String& operator=(LPCXSSTR s) {if (s) super::assign(s); else erase(); return *this;} XS_String& operator=(const super& s) {super::assign(s); return *this;} void assign(LPCXSSTR s) {super::assign(s);} - void assign(LPCXSSTR s, int l) {super::assign(s, l);} + void assign(LPCXSSTR s, size_t l) {super::assign(s, l);} operator LPCXSSTR() const {return c_str();} #ifdef XS_STRING_UTF8 - operator std::wstring() const {int bl=length(); LPWSTR b=(LPWSTR)alloca(sizeof(WCHAR)*bl); return std::wstring(b, MultiByteToWideChar(CP_UTF8, 0, c_str(), bl, b, bl));} + 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));} #elif defined(UNICODE) - operator std::string() const {int bl=length(); LPSTR b=(LPSTR)alloca(bl); return std::string(b, WideCharToMultiByte(CP_ACP, 0, c_str(), bl, b, bl, 0, 0));} + 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));} #else - operator std::wstring() const {int bl=length(); LPWSTR b=(LPWSTR)alloca(sizeof(WCHAR)*bl); return std::wstring(b, MultiByteToWideChar(CP_ACP, 0, c_str(), bl, b, bl));} + 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));} #endif XS_String& printf(LPCXSSTR fmt, ...) @@ -169,7 +280,7 @@ struct XS_String XS_CHAR b[BUFFER_LEN]; va_start(l, fmt); - super::assign(b, XS_vsprintf(b, fmt, l)); + super::assign(b, XS_vsnprintf(b, COUNTOF(b), fmt, l)); va_end(l); return *this; @@ -179,7 +290,7 @@ struct XS_String { XS_CHAR b[BUFFER_LEN]; - super::assign(b, XS_vsprintf(b, fmt, l)); + super::assign(b, XS_vsnprintf(b, COUNTOF(b), fmt, l)); return *this; } @@ -190,7 +301,7 @@ struct XS_String XS_CHAR b[BUFFER_LEN]; va_start(l, fmt); - super::append(b, XS_vsprintf(b, fmt, l)); + super::append(b, XS_vsnprintf(b, COUNTOF(b), fmt, l)); va_end(l); return *this; @@ -200,7 +311,7 @@ struct XS_String { XS_CHAR b[BUFFER_LEN]; - super::append(b, XS_vsprintf(b, fmt, l)); + super::append(b, XS_vsnprintf(b, COUNTOF(b), fmt, l)); return *this; } @@ -211,12 +322,33 @@ struct XS_String #endif // XS_String +#define XS_EMPTY_STR XS_TEXT("") +#define XS_TRUE_STR XS_TEXT("true") +#define XS_FALSE_STR XS_TEXT("false") +#define XS_INTFMT_STR XS_TEXT("%d") +#define XS_FLOATFMT_STR XS_TEXT("%f") + + // work around GCC's wide string constant bug +#ifdef __GNUC__ +extern const LPCXSSTR XS_EMPTY; +extern const LPCXSSTR XS_TRUE; +extern const LPCXSSTR XS_FALSE; +extern const LPCXSSTR XS_INTFMT; +extern const LPCXSSTR XS_FLOATFMT; +#else +#define XS_EMPTY XS_EMPTY_STR +#define XS_TRUE XS_TRUE_STR +#define XS_FALSE XS_FALSE_STR +#define XS_INTFMT XS_INTFMT_STR +#define XS_FLOATFMT XS_FLOATFMT_STR +#endif + + #ifndef XS_STRING_UTF8 -inline void assign_utf8(XS_String& s, const char* str) + // from UTF-8 to XS internal string encoding +inline void assign_utf8(XS_String& s, const char* str, int lutf8) { - int lutf8 = strlen(str); - #ifdef UNICODE LPTSTR buffer = (LPTSTR)alloca(sizeof(TCHAR)*lutf8); int l = MultiByteToWideChar(CP_UTF8, 0, str, lutf8, buffer, lutf8); @@ -231,22 +363,44 @@ inline void assign_utf8(XS_String& s, const char* str) s.assign(buffer, l); } -inline std::string get_utf8(LPCTSTR s, int l) + // from UTF-8 to XS internal string encoding +inline void assign_utf8(XS_String& s, const char* str) +{ + assign_utf8(s, str, strlen(str)); +} + + // from XS internal string encoding to UTF-8 +inline std::string get_utf8(LPCTSTR s, size_t l) { #ifdef UNICODE - int bl=2*l; LPSTR buffer = (LPSTR)alloca(bl); - l = WideCharToMultiByte(CP_UTF8, 0, s, l, buffer, bl, 0, 0); + size_t bl=2*l; LPSTR buffer = (LPSTR)alloca(bl); + l = WideCharToMultiByte(CP_UTF8, 0, s, (int)l, buffer, (int)bl, 0, 0); #else LPWSTR wbuffer = (LPWSTR)alloca(sizeof(WCHAR)*l); - l = MultiByteToWideChar(CP_ACP, 0, s, l, wbuffer, l); + l = MultiByteToWideChar(CP_ACP, 0, s, (int)l, wbuffer, (int)l); - int bl=2*l; LPSTR buffer = (LPSTR)alloca(bl); - l = WideCharToMultiByte(CP_UTF8, 0, wbuffer, l, buffer, bl, 0, 0); + size_t bl=2*l; LPSTR buffer = (LPSTR)alloca(bl); + l = WideCharToMultiByte(CP_UTF8, 0, wbuffer, (int)l, buffer, (int)bl, 0, 0); #endif return std::string(buffer, l); } +#ifdef UNICODE + // from XS internal string encoding to UTF-8 +inline std::string get_utf8(const char* s, size_t l) +{ + LPWSTR wbuffer = (LPWSTR)alloca(sizeof(WCHAR)*l); + l = MultiByteToWideChar(CP_ACP, 0, s, (int)l, wbuffer, (int)l); + + size_t bl=2*l; LPSTR buffer = (LPSTR)alloca(bl); + l = WideCharToMultiByte(CP_UTF8, 0, wbuffer, (int)l, buffer, (int)bl, 0, 0); + + return std::string(buffer, l); +} +#endif + + // from XS internal string encoding to UTF-8 inline std::string get_utf8(const XS_String& s) { return get_utf8(s.c_str(), s.length()); @@ -265,23 +419,19 @@ typedef __gnu_cxx::stdio_filebuf STDIO_FILEBUF; typedef std::filebuf STDIO_FILEBUF; #endif - /// input file stream with ANSI/UNICODE file names -struct tifstream : public std::istream +struct FileHolder { - typedef std::istream super; - - tifstream(LPCTSTR path) - : super(&_buf), - _pfile(_tfopen(path, TEXT("r"))), -#ifdef __GNUC__ - _buf(_pfile, ios::in) -#else - _buf(_pfile) -#endif + FileHolder(LPCTSTR path, LPCTSTR mode) { +#ifdef __STDC_WANT_SECURE_LIB__ // secure CRT functions using VS 2005 + if (_tfopen_s(&_pfile, path, mode) != 0) + _pfile = NULL; +#else + _pfile = _tfopen(path, mode); +#endif } - ~tifstream() + ~FileHolder() { if (_pfile) fclose(_pfile); @@ -289,19 +439,38 @@ struct tifstream : public std::istream protected: FILE* _pfile; +}; + + /// input file stream with ANSI/UNICODE file names +struct tifstream : public std::istream, FileHolder +{ + typedef std::istream super; + + tifstream(LPCTSTR path) + : super(&_buf), + FileHolder(path, TEXT("rb")), // binary mode is important for XMLReader::read_buffer() with MinGW libraries +#ifdef __GNUC__ + _buf(_pfile, std::ios::in) +#else + _buf(_pfile) +#endif + { + } + +protected: STDIO_FILEBUF _buf; }; /// output file stream with ANSI/UNICODE file names -struct tofstream : public std::ostream +struct tofstream : public std::ostream, FileHolder { typedef std::ostream super; tofstream(LPCTSTR path) : super(&_buf), - _pfile(_tfopen(path, TEXT("w"))), + FileHolder(path, TEXT("wb")), #ifdef __GNUC__ - _buf(_pfile, ios::out) + _buf(_pfile, std::ios::out) #else _buf(_pfile) #endif @@ -311,13 +480,9 @@ struct tofstream : public std::ostream ~tofstream() { flush(); - - if (_pfile) - fclose(_pfile); } protected: - FILE* _pfile; STDIO_FILEBUF _buf; }; @@ -326,16 +491,17 @@ protected: #define XML_INDENT_SPACE " " -#ifdef XML_UNICODE // Are XML_Char strings UTF-16 encoded? +#if defined(XS_USE_XERCES) || defined(XS_USE_EXPAT) +#if defined(XML_UNICODE)/*Expat*/ || defined(XS_USE_XERCES)/*Xerces*/ // Are Expat/Xerces XML strings UTF-16 encoded? typedef XS_String String_from_XML_Char; #elif defined(XS_STRING_UTF8) - typedef XS_String String_from_XML_Char; #else + /// converter from Expat/Xerces strings to XMLStorage internal strings struct String_from_XML_Char : public XS_String { String_from_XML_Char(const XML_Char* str) @@ -346,6 +512,8 @@ struct String_from_XML_Char : public XS_String #endif +#endif // defined(XS_USE_XERCES) || defined(XS_USE_EXPAT) + #if defined(UNICODE) && !defined(XS_STRING_UTF8) @@ -365,6 +533,152 @@ inline bool operator==(const XS_String& s1, const char* s2) #endif + /// XML Error with message and location +struct XMLError +{ + XMLError() + : _line(0), + _column(0), + _error_code(0) + { + } + + std::string str() const; + friend std::ostream& operator<<(std::ostream&, const XMLError& err); + + XS_String _message; + XS_String _systemId; + int _line; + int _column; + int _error_code; +}; + +struct XMLErrorList : public std::list +{ + XS_String str() const; +}; + + +#ifdef XMLNODE_LOCATION + /// location of XML Node including XML file name +struct XMLLocation +{ + XMLLocation() + : _pdisplay_path(NULL), + _line(0), + _column(0) + { + } + + XMLLocation(const char* display_path, int line, int column) + : _pdisplay_path(display_path), + _line(line), + _column(column) + { + } + + std::string str() const; + +protected: + const char* _pdisplay_path; // character pointer for fast reference + int _line; + int _column; +}; +#endif + + +enum PRETTY_FLAGS { + PRETTY_PLAIN = 0, + PRETTY_LINEFEED = 1, + PRETTY_INDENT = 2 +}; + + +struct StyleSheet +{ + std::string _href; // CDATA #REQUIRED + std::string _type; // CDATA #REQUIRED + std::string _title; // CDATA #IMPLIED + std::string _media; // CDATA #IMPLIED + std::string _charset; // CDATA #IMPLIED + bool _alternate; // (yes|no) "no" + + StyleSheet() : _alternate(false) {} + + StyleSheet(const std::string& href, const std::string& type="text/xsl", bool alternate=false) + : _href(href), + _type(type), + _alternate(alternate) + { + } + + bool empty() const {return _href.empty();} + void print(std::ostream& out) const; +}; + +struct StyleSheetList : public std::list +{ + void set(const StyleSheet& stylesheet) + { + clear(); + push_back(stylesheet); + } +}; + + +struct DocType +{ + std::string _name; + + // External Document Types are noted, but not parsed. + std::string _public; + std::string _system; + + // Internal DTDs are not supported. + + void parse(const char* str); + bool empty() const {return _name.empty();} +}; + + /// Management of XML file headers and formating +struct XMLFormat +{ + XMLFormat(PRETTY_FLAGS pretty=PRETTY_INDENT, const std::string& xml_version="1.0", const std::string& encoding="utf-8", const DocType& doctype=DocType()) + : _pretty(pretty), + _endl("\n"), + _version(xml_version), + _encoding(encoding), + _doctype(doctype), + _standalone(-1) + { + } + + void print_header(std::ostream& out, bool lf=true) const; + + PRETTY_FLAGS _pretty; + const char* _endl; // line ending string: "\n" or "\r\n" + + std::string _version; + std::string _encoding; + + DocType _doctype; + + StyleSheetList _stylesheets; + +// std::string _additional; + + int _standalone; +}; + + +enum WRITE_MODE { + FORMAT_PLAIN, /// write XML without any white space + FORMAT_SMART, /// preserve original white space and comments if present; pretty print otherwise + FORMAT_ORIGINAL, /// write XML stream preserving original white space and comments + FORMAT_PRETTY /// pretty print node to stream without preserving original white space +}; + + /// in memory representation of an XML node struct XMLNode : public XS_String { @@ -392,11 +706,33 @@ struct XMLNode : public XS_String { return super::find(x); } + + XS_String get(const char* x, LPXSSTR def=XS_EMPTY_STR) const + { + const_iterator found = find(x); + + if (found != end()) + return found->second; + else + return def; + } }; #else - typedef std::map AttributeMap; + struct AttributeMap : public std::map + { + XS_String get(const char* x, LPXSSTR def=XS_EMPTY_STR) const + { + const_iterator found = find(x); + + if (found != end()) + return found->second; + else + return def; + } + }; #endif + /// internal children node list struct Children : public std::list { void assign(const Children& other) @@ -436,17 +772,21 @@ struct XMLNode : public XS_String } XMLNode(const XMLNode& other) - : _attributes(other._attributes), + : XS_String(other), + _attributes(other._attributes), _leading(other._leading), _content(other._content), _end_leading(other._end_leading), _trailing(other._trailing) +#ifdef XMLNODE_LOCATION + , _location(other._location) +#endif { for(Children::const_iterator it=other._children.begin(); it!=other._children.end(); ++it) _children.push_back(new XMLNode(**it)); } - ~XMLNode() + virtual ~XMLNode() { while(!_children.empty()) { delete _children.back(); @@ -500,14 +840,14 @@ struct XMLNode : public XS_String } /// read only access to an attribute - template XS_String get(const T& attr_name) const + template XS_String get(const T& attr_name, LPXSSTR def=XS_EMPTY_STR) const { AttributeMap::const_iterator found = _attributes.find(attr_name); if (found != _attributes.end()) return found->second; else - return XS_String(); + return def; } /// convenient value access in children node @@ -570,13 +910,23 @@ struct XMLNode : public XS_String return _children; } + const AttributeMap& get_attributes() const + { + return _attributes; + } + + AttributeMap& get_attributes() + { + return _attributes; + } + XS_String get_content() const { #ifdef XS_STRING_UTF8 const XS_String& ret = _content; #else XS_String ret; - assign_utf8(ret, _content.c_str()); + assign_utf8(ret, _content.c_str(), _content.length()); #endif return DecodeXMLString(ret.c_str()); @@ -587,18 +937,20 @@ struct XMLNode : public XS_String _content.assign(EncodeXMLString(s.c_str())); } - enum WRITE_MODE { - FORMAT_SMART = 0, /// preserve original white space and comments if present; pretty print otherwise - FORMAT_ORIGINAL = 1, /// write XML stream preserving original white space and comments - FORMAT_PRETTY = 2 /// pretty print node to stream without preserving original white space - }; +#ifdef XMLNODE_LOCATION + const XMLLocation& get_location() const {return _location;} +#endif /// write node with children tree to output stream - std::ostream& write(std::ostream& out, WRITE_MODE mode=FORMAT_SMART, int indent=0) const + std::ostream& write(std::ostream& out, const XMLFormat& format, WRITE_MODE mode=FORMAT_SMART, int indent=0) const { switch(mode) { + case FORMAT_PLAIN: + plain_write_worker(out); + break; + case FORMAT_PRETTY: - pretty_write_worker(out, indent); + pretty_write_worker(out, format, indent); break; case FORMAT_ORIGINAL: @@ -606,7 +958,7 @@ struct XMLNode : public XS_String break; default: // FORMAT_SMART - smart_write_worker(out, indent); + smart_write_worker(out, format, indent); } return out; @@ -616,10 +968,14 @@ protected: Children _children; AttributeMap _attributes; - std::string _leading; - std::string _content; - std::string _end_leading; - std::string _trailing; + std::string _leading; // UTF-8 encoded + std::string _content; // UTF-8 and entity encoded, may contain CDATA sections; decode with DecodeXMLString() + std::string _end_leading; // UTF-8 encoded + std::string _trailing; // UTF-8 encoded + +#ifdef XMLNODE_LOCATION + XMLLocation _location; +#endif XMLNode* get_first_child() const { @@ -678,18 +1034,20 @@ protected: } #endif - /// XPath find functions + /// XPath find function (const) const XMLNode* find_relative(const char* path) const; + /// XPath find function XMLNode* find_relative(const char* path) {return const_cast(const_cast(this)->find_relative(path));} /// relative XPath create function XMLNode* create_relative(const char* path); - void write_worker(std::ostream& out, int indent) const; - void pretty_write_worker(std::ostream& out, int indent) const; - void smart_write_worker(std::ostream& out, int indent) const; + void write_worker(std::ostream& out, int indent) const; + void plain_write_worker(std::ostream& out) const; + void pretty_write_worker(std::ostream& out, const XMLFormat& format, int indent) const; + void smart_write_worker(std::ostream& out, const XMLFormat& format, int indent) const; }; @@ -708,6 +1066,7 @@ struct XMLChildrenFilter { } + /// internal iterator class struct iterator { typedef XMLNode::Children::iterator BaseIterator; @@ -806,6 +1165,7 @@ struct const_XMLChildrenFilter { } + /// internal iterator class struct const_iterator { typedef XMLNode::Children::const_iterator BaseIterator; @@ -954,6 +1314,7 @@ struct XMLPos return _cur->get(attr_name); } + /// attribute setting void put(const XS_String& attr_name, const XS_String& value) { _cur->put(attr_name, value); @@ -1218,18 +1579,7 @@ protected: }; - // work around GCC's wide string constant bug -#ifdef __GNUC__ -extern const LPCXSSTR XS_TRUE; -extern const LPCXSSTR XS_FALSE; -extern const LPCXSSTR XS_NUMBERFMT; -#else -#define XS_TRUE XS_TEXT("true") -#define XS_FALSE XS_TEXT("false") -#define XS_NUMBERFMT XS_TEXT("%d") -#endif - - + /// type converter for boolean data struct XMLBool { XMLBool(bool value=false) @@ -1277,6 +1627,7 @@ private: void operator=(const XMLBool&); // disallow assignment operations }; + /// type converter for boolean data with write access struct XMLBoolRef { XMLBoolRef(XMLNode* node, const XS_String& attr_name, bool def=false) @@ -1318,6 +1669,7 @@ protected: }; + /// type converter for integer data struct XMLInt { XMLInt(int value) @@ -1351,7 +1703,7 @@ struct XMLInt operator XS_String() const { XS_CHAR buffer[32]; - XS_sprintf(buffer, XS_NUMBERFMT, _value); + XS_snprintf(buffer, COUNTOF(buffer), XS_INTFMT, _value); return buffer; } @@ -1362,6 +1714,7 @@ private: void operator=(const XMLInt&); // disallow assignment operations }; + /// type converter for integer data with write access struct XMLIntRef { XMLIntRef(XMLNode* node, const XS_String& attr_name, int def=0) @@ -1386,7 +1739,7 @@ struct XMLIntRef void assign(int value) { XS_CHAR buffer[32]; - XS_sprintf(buffer, XS_NUMBERFMT, value); + XS_snprintf(buffer, COUNTOF(buffer), XS_INTFMT, value); _ref.assign(buffer); } @@ -1395,6 +1748,90 @@ protected: }; + /// type converter for numeric data +struct XMLDouble +{ + XMLDouble(double value) + : _value(value) + { + } + + XMLDouble(LPCXSSTR value, double def=0.) + { + LPTSTR end; + + if (value && *value) + _value = XS_tod(value, &end); + else + _value = def; + } + + XMLDouble(const XMLNode* node, const XS_String& attr_name, double def=0.) + { + LPTSTR end; + const XS_String& value = node->get(attr_name); + + if (!value.empty()) + _value = XS_tod(value.c_str(), &end); + else + _value = def; + } + + operator double() const + { + return _value; + } + + operator XS_String() const + { + XS_CHAR buffer[32]; + XS_snprintf(buffer, COUNTOF(buffer), XS_FLOATFMT, _value); + return buffer; + } + +protected: + double _value; + +private: + void operator=(const XMLDouble&); // disallow assignment operations +}; + + /// type converter for numeric data with write access +struct XMLDoubleRef +{ + XMLDoubleRef(XMLNode* node, const XS_String& attr_name, double def=0.) + : _ref((*node)[attr_name]) + { + if (_ref.empty()) + assign(def); + } + + XMLDoubleRef& operator=(double value) + { + assign(value); + + return *this; + } + + operator double() const + { + LPTSTR end; + return XS_tod(_ref.c_str(), &end); + } + + void assign(double value) + { + XS_CHAR buffer[32]; + XS_snprintf(buffer, COUNTOF(buffer), XS_FLOATFMT, value); + _ref.assign(buffer); + } + +protected: + XS_String& _ref; +}; + + + /// type converter for string data struct XMLString { XMLString(const XS_String& value) @@ -1402,7 +1839,7 @@ struct XMLString { } - XMLString(LPCXSSTR value, LPCXSSTR def=XS_TEXT("")) + XMLString(LPCXSSTR value, LPCXSSTR def=XS_EMPTY) { if (value && *value) _value = value; @@ -1410,7 +1847,7 @@ struct XMLString _value = def; } - XMLString(const XMLNode* node, const XS_String& attr_name, LPCXSSTR def=XS_TEXT("")) + XMLString(const XMLNode* node, const XS_String& attr_name, LPCXSSTR def=XS_EMPTY) { const XS_String& value = node->get(attr_name); @@ -1437,16 +1874,17 @@ private: void operator=(const XMLString&); // disallow assignment operations }; + /// type converter for string data with write access struct XMStringRef { - XMStringRef(XMLNode* node, const XS_String& attr_name, LPCXSSTR def=XS_TEXT("")) + XMStringRef(XMLNode* node, const XS_String& attr_name, LPCXSSTR def=XS_EMPTY) : _ref((*node)[attr_name]) { if (_ref.empty()) assign(def); } - XMStringRef(XMLNode* node, const XS_String& node_name, const XS_String& attr_name, LPCXSSTR def=XS_TEXT("")) + XMStringRef(XMLNode* node, const XS_String& node_name, const XS_String& attr_name, LPCXSSTR def=XS_EMPTY) : _ref(node->subvalue(node_name, attr_name)) { if (_ref.empty()) @@ -1500,65 +1938,151 @@ template<> /// XML reader base class struct XMLReaderBase +#ifdef XS_USE_XERCES + : public HandlerBase +#endif { - XMLReaderBase(XMLNode* node) - : _pos(node), - _parser(XML_ParserCreate(NULL)) - { - XML_SetUserData(_parser, this); - XML_SetXmlDeclHandler(_parser, XML_XmlDeclHandler); - XML_SetElementHandler(_parser, XML_StartElementHandler, XML_EndElementHandler); - XML_SetDefaultHandler(_parser, XML_DefaultHandler); +#ifdef XS_USE_XERCES - _last_tag = TAG_NONE; - } + XMLReaderBase(XMLNode* node, InputSource* source, bool adoptSource=false); + virtual ~XMLReaderBase(); - virtual ~XMLReaderBase() - { - XML_ParserFree(_parser); - } - - XML_Status read(); - - virtual int read_buffer(char* buffer, int len) = 0; - - std::string get_position() const - { - int line = XML_GetCurrentLineNumber(_parser); - int column = XML_GetCurrentColumnNumber(_parser); - - std::ostringstream out; - out << "(" << line << ") : [column " << column << "]"; - - return out.str(); - } - - std::string get_instructions() const {return _instructions;} - - XML_Error get_error_code() {return XML_GetErrorCode(_parser);} - std::string get_error_string() const; + void read(); + +protected: + SAXParser* _parser; + InputSource* _source; + bool _deleteSource; + + virtual void XMLDecl(const XMLCh* const versionStr, const XMLCh* const encodingStr, + const XMLCh* const standaloneStr, const XMLCh* const actualEncodingStr); + + // Handlers for the SAX DocumentHandler interface + virtual void setDocumentLocator(const Locator* const locator); + virtual void startElement(const XMLCh* const name, AttributeList& attributes); + virtual void endElement(const XMLCh* const name); + virtual void characters(const XMLCh* const chars, const unsigned int length); + virtual void ignorableWhitespace(const XMLCh* const chars, const unsigned int length); + + // Handlers for the SAX ErrorHandler interface + virtual void error(const SAXParseException& e); + virtual void fatalError(const SAXParseException& e); + virtual void warning(const SAXParseException& e); + virtual void resetErrors(); + +#elif defined(XS_USE_EXPAT) // !XS_USE_XERCES + + XMLReaderBase(XMLNode* node); + virtual ~XMLReaderBase(); protected: - XMLPos _pos; XML_Parser _parser; - std::string _xml_version; - std::string _encoding; - std::string _instructions; - std::string _content; - enum {TAG_NONE, TAG_START, TAG_END} _last_tag; - - static void XMLCALL XML_XmlDeclHandler(void* userData, const XML_Char* version, const XML_Char* encoding, int standalone); + static void XMLCALL XML_XmlDeclHandler(void* userData, const XML_Char* version, const XML_Char* encoding, int standalone=-1); static void XMLCALL XML_StartElementHandler(void* userData, const XML_Char* name, const XML_Char** atts); static void XMLCALL XML_EndElementHandler(void* userData, const XML_Char* name); static void XMLCALL XML_DefaultHandler(void* userData, const XML_Char* s, int len); + + static std::string get_expat_error_string(XML_Error error_code); + +#else // XS_USE_EXPAT + + XMLReaderBase(XMLNode* node) + : _pos(node), + _endl_defined(false), + _utf8(false) + { + _last_tag = TAG_NONE; + } + + virtual ~XMLReaderBase(); + + bool parse(); + +#endif + +public: +#ifndef XS_USE_XERCES + void read(); + + std::string get_position() const; +#endif + const XMLFormat& get_format() const {return _format;} + const char* get_endl() const {return _endl_defined? _format._endl: "\n";} + + const XMLErrorList& get_errors() const {return _errors;} + const XMLErrorList& get_warnings() const {return _warnings;} + + void clear_errors() {_errors.clear(); _warnings.clear();} + +#ifdef XMLNODE_LOCATION + const char* _display_path; // character pointer for fast reference in XMLLocation + +#ifdef XS_USE_XERCES + const Locator* _locator; +#endif + + XMLLocation get_location() const; +#endif + +protected: + XMLPos _pos; + + std::string _content; // UTF-8 encoded + enum {TAG_NONE, TAG_START, TAG_END} _last_tag; + + XMLErrorList _errors; + XMLErrorList _warnings; + + XMLFormat _format; + bool _endl_defined; + +#ifdef XS_USE_XERCES + //@@ +#elif defined(XS_USE_EXPAT) + virtual int read_buffer(char* buffer, int len) = 0; +#else + virtual int get() = 0; + int eat_endl(); + + bool _utf8; +#endif + + void finish_read(); + + virtual void XmlDeclHandler(const char* version, const char* encoding, int standalone); + virtual void StartElementHandler(const XS_String& name, const XMLNode::AttributeMap& attributes); + virtual void EndElementHandler(); +#if defined(XS_USE_XERCES) || defined(XS_USE_EXPAT) + virtual void DefaultHandler(const XML_Char* s, int len); +#else + virtual void DefaultHandler(const std::string& s); +#endif }; /// XML file reader -struct XMLReader : public XMLReaderBase + +#ifdef XS_USE_XERCES + +struct XercesXMLReader : public XMLReaderBase { - XMLReader(XMLNode* node, std::istream& in) + XercesXMLReader(XMLNode* node, InputSource* source, bool adoptSource=false) + : XMLReaderBase(node, source, adoptSource) + { + } + + XercesXMLReader(XMLNode* node, LPCTSTR path); + XercesXMLReader(XMLNode* node, const XMLByte* buffer, size_t bytes, const std::string& system_id=std::string()); +}; + +#define XMLReader XercesXMLReader + +#elif defined(XS_USE_EXPAT) + +struct ExpatXMLReader : public XMLReaderBase +{ + ExpatXMLReader(XMLNode* node, std::istream& in) : XMLReaderBase(node), _in(in) { @@ -1579,112 +2103,122 @@ protected: std::istream& _in; }; +#define XMLReader ExpatXMLReader -struct XMLHeader +#else // XS_USE_XERCES, XS_USE_EXPAT + +struct XMLReader : public XMLReaderBase { - XMLHeader(const std::string& xml_version="1.0", const std::string& encoding="UTF-8", const std::string& doctype="") - : _version(xml_version), - _encoding(encoding), - _doctype(doctype) + XMLReader(XMLNode* node, std::istream& in) + : XMLReaderBase(node), + _in(in) { } - void print(std::ostream& out) const + /// read one character from XML stream + int get() { - out << "\n"; - - if (!_doctype.empty()) - out << _doctype << '\n'; - if (!_additional.empty()) - out << _additional << '\n'; + return _in.get(); } - std::string _version; - std::string _encoding; - std::string _doctype; - std::string _additional; +protected: + std::istream& _in; }; +#endif // XS_USE_XERCES + + /// XML document holder struct XMLDoc : public XMLNode { XMLDoc() - : XMLNode(""), - _last_error(XML_ERROR_NONE) + : XMLNode("") { } XMLDoc(LPCTSTR path) - : XMLNode(""), - _last_error(XML_ERROR_NONE) + : XMLNode("") { read(path); } - std::istream& read(std::istream& in) +#ifdef XS_USE_XERCES + bool read(LPCTSTR path) { - XMLReader reader(this, in); + XMLReader reader(this, path); - read(reader); - - return in; +#if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8) + return read(reader, std::string(ANS(path))); +#else + return read(reader, XS_String(path)); +#endif } + bool read(const char* buffer, size_t len, const std::string& system_id=std::string()) + { + XMLReader reader(this, (const XMLByte*)buffer, len, system_id); + + return read(reader, system_id); + } + +#else // XS_USE_XERCES + bool read(LPCTSTR path) { tifstream in(path); XMLReader reader(this, in); -//#if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8) -// return read(reader, std::string(ANS(path))); -//#else +#if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8) + return read(reader, std::string(ANS(path))); +#else return read(reader, XS_String(path)); -//#endif +#endif } - bool read(XMLReaderBase& reader) + bool read(const char* buffer, size_t len, const std::string& system_id=std::string()) { - XML_Status status = reader.read(); + std::istringstream in(std::string(buffer, len)); - _header._additional = reader.get_instructions(); - - if (status == XML_STATUS_ERROR) { - std::ostringstream out; - - out << "input stream" << reader.get_position() << " " << reader.get_error_string(); - - _last_error = reader.get_error_code(); - _last_error_msg = out.str(); - } - - return status != XML_STATUS_ERROR; + return read(in, system_id); } + bool read(std::istream& in, const std::string& system_id=std::string()) + { + XMLReader reader(this, in); + + return read(reader, system_id); + } +#endif // XS_USE_XERCES + bool read(XMLReaderBase& reader, const std::string& display_path) { - XML_Status status = reader.read(); +#ifdef XMLNODE_LOCATION + // make a string copy to handle temporary string objects + _display_path = display_path; + reader._display_path = _display_path.c_str(); +#endif - _header._additional = reader.get_instructions(); + reader.clear_errors(); + reader.read(); - if (status == XML_STATUS_ERROR) { - std::ostringstream out; + _format = reader.get_format(); + _format._endl = reader.get_endl(); - out << display_path << reader.get_position() << " " << reader.get_error_string(); - - _last_error = reader.get_error_code(); - _last_error_msg = out.str(); + if (!reader.get_errors().empty()) { + _errors = reader.get_errors(); + return false; } - return status != XML_STATUS_ERROR; + return true; } /// write XML stream preserving previous white space and comments std::ostream& write(std::ostream& out, WRITE_MODE mode=FORMAT_SMART) const { - _header.print(out); + _format.print_header(out, mode!=FORMAT_PLAIN); if (!_children.empty()) - _children.front()->write(out); + _children.front()->write(out, _format, mode); return out; } @@ -1695,26 +2229,30 @@ struct XMLDoc : public XMLNode return write(out, FORMAT_PRETTY); } - void write(LPCTSTR path, WRITE_MODE mode=FORMAT_SMART) const + bool write(LPCTSTR path, WRITE_MODE mode=FORMAT_SMART) const { tofstream out(path); - write(out, mode); + return write(out, mode).good(); } - void write_formating(LPCTSTR path) const + bool write_formating(LPCTSTR path) const { tofstream out(path); - write_formating(out); + return write_formating(out).good(); } - XMLHeader _header; - XML_Error _last_error; - std::string _last_error_msg; + XMLFormat _format; + XMLErrorList _errors; + +#ifdef XMLNODE_LOCATION + std::string _display_path; +#endif }; + /// XML message wrapper struct XMLMessage : public XMLDoc { XMLMessage(const char* name) @@ -1723,7 +2261,212 @@ struct XMLMessage : public XMLDoc _pos.create(name); } + std::string toString() const + { + std::ostringstream out; + + write(out); + + return out.str(); + } + XMLPos _pos; + +protected: + XMLMessage() + : _pos(this) + { + } +}; + + +struct XMLMessageFromString : public XMLMessage +{ + XMLMessageFromString(const std::string& xml_str, const std::string& system_id=std::string()) + { + read(xml_str.c_str(), xml_str.length(), system_id); + } +}; + + + /// Reader for XML Messages +struct XMLMessageReader : public XMLPos +{ + XMLMessageReader(const std::string& xml_str, const std::string& system_id=std::string()) + : XMLPos(&_msg) + { + _msg.read(xml_str.c_str(), xml_str.length(), system_id); + } + + const XMLDoc& get_document() + { + return _msg; + } + +protected: + XMLDoc _msg; +}; + + +struct XMLWriter +{ + XMLWriter(std::ostream& out, const XMLFormat& format=XMLFormat()) + : _pofstream(NULL), + _out(out), + _format(format) + { + format.print_header(_out, false); // _format._endl is printed in write_pre() + } + + XMLWriter(LPCTSTR path, const XMLFormat& format=XMLFormat()) + : _pofstream(new tofstream(path)), + _out(*_pofstream), + _format(format) + { + format.print_header(_out, false); // _format._endl is printed in write_pre() + } + + ~XMLWriter() + { + _out << _format._endl; + delete _pofstream; + } + + /// create node and move to it + void create(const XS_String& name) + { + if (!_stack.empty()) { + StackEntry& last = _stack.top(); + + if (last._state < PRE_CLOSED) { + write_attributes(last); + close_pre(last); + } + + ++last._children; + } + + StackEntry entry; + entry._node_name = name; + _stack.push(entry); + + write_pre(entry); + } + + /// go back to previous position + bool back() + { + if (!_stack.empty()) { + write_post(_stack.top()); + + _stack.pop(); + return true; + } else + return false; + } + + /// attribute setting + void put(const XS_String& attr_name, const XS_String& value) + { + if (!_stack.empty()) + _stack.top()._attributes[attr_name] = value; + } + + /// C++ write access to an attribute + XS_String& operator[](const XS_String& attr_name) + { + if (_stack.empty()) + return s_empty_attr; + + return _stack.top()._attributes[attr_name]; + } + + void set_content(const XS_String& s) + { + if (!_stack.empty()) + _stack.top()._content = EncodeXMLString(s.c_str()); + } + + // public for access in StackEntry + enum WRITESTATE { + NOTHING, /*PRE,*/ ATTRIBUTES, PRE_CLOSED, /*CONTENT,*/ POST + }; + +protected: + tofstream* _pofstream; + std::ostream& _out; + const XMLFormat&_format; + + typedef XMLNode::AttributeMap AttrMap; + + struct StackEntry { + XS_String _node_name; + AttrMap _attributes; + std::string _content; + WRITESTATE _state; + bool _children; + + StackEntry() : _state(NOTHING), _children(false) {} + }; + + std::stack _stack; + + static XS_String s_empty_attr; + + void close_pre(StackEntry& entry) + { + _out << '>'; + + entry._state = PRE_CLOSED; + } + + void write_pre(StackEntry& entry) + { + if (_format._pretty >= PRETTY_LINEFEED) + _out << _format._endl; + + if (_format._pretty == PRETTY_INDENT) + for(size_t i=_stack.size(); --i>0; ) + _out << XML_INDENT_SPACE; + + _out << '<' << EncodeXMLString(entry._node_name); + //entry._state = PRE; + } + + void write_attributes(StackEntry& entry) + { + for(AttrMap::const_iterator it=entry._attributes.begin(); it!=entry._attributes.end(); ++it) + _out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\""; + + entry._state = ATTRIBUTES; + } + + void write_post(StackEntry& entry) + { + if (entry._state < ATTRIBUTES) + write_attributes(entry); + + if (entry._children || !entry._content.empty()) { + if (entry._state < PRE_CLOSED) + close_pre(entry); + + _out << entry._content; + //entry._state = CONTENT; + + if (_format._pretty>=PRETTY_LINEFEED && entry._content.empty()) + _out << _format._endl; + + if (_format._pretty==PRETTY_INDENT && entry._content.empty()) + for(size_t i=_stack.size(); --i>0; ) + _out << XML_INDENT_SPACE; + + _out << ""; + } else { + _out << "/>"; + } + + entry._state = POST; + } }; diff --git a/reactos/base/applications/ibrowser/utility/xs-native.cpp b/reactos/base/applications/ibrowser/utility/xs-native.cpp new file mode 100644 index 00000000000..90f5bea5852 --- /dev/null +++ b/reactos/base/applications/ibrowser/utility/xs-native.cpp @@ -0,0 +1,438 @@ + + // + // XML storage classes + // + // xs-native.cpp + // + // Copyright (c) 2006 Martin Fuchs + // + + +/* + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef XS_NO_COMMENT +#define XS_NO_COMMENT // no #pragma comment(lib, ...) statements in .lib files to enable static linking +#endif + +//#include "xmlstorage.h" +#include + + +#if !defined(XS_USE_EXPAT) && !defined(XS_USE_XERCES) + +namespace XMLStorage { + + +XMLReaderBase::~XMLReaderBase() +{ +} + + /// read XML stream into XML tree below _pos +void XMLReaderBase::read() +{ + if (!parse()) { + XMLError error; + + error._message = "XML parsing error"; + //error._line = ; + //error._column = ; + + _errors.push_back(error); + } + + finish_read(); +} + + +struct Buffer +{ + Buffer() + { + _buffer = (char*) malloc(BUFFER_LEN); + _len = BUFFER_LEN; + + reset(); + } + + ~Buffer() + { + free(_buffer); + } + + void reset() + { + _wptr = _buffer; + _buffer_str.erase(); + } + + void append(char c) + { + size_t wpos = _wptr-_buffer; + + if (wpos >= _len) { + _len <<= 1; + _buffer = (char*) realloc(_buffer, _len); + _wptr = _buffer + wpos; + } + + *_wptr++ = c; + } + + const std::string& str(bool utf8) // returns UTF-8 encoded buffer content + { + if (utf8) + _buffer_str.assign(_buffer, _wptr-_buffer); + else + _buffer_str = get_utf8(_buffer, _wptr-_buffer); + + return _buffer_str; + } + + size_t len() const + { + return _wptr - _buffer; + } + + bool has_CDEnd() const + { + //if (_wptr-_buffer < 3) + // return false; + + return !strncmp(_wptr-3, "]]>", 3); + } + + XS_String get_tag() const + { + const char* p = _buffer_str.c_str(); + + if (*p == '<') + ++p; + + if (*p == '/') + ++p; + + const char* q = p; + + if (*q == '?') + ++q; + + while(isxmlsym(*q)) + ++q; + +#ifdef XS_STRING_UTF8 + return XS_String(p, q-p); +#else + XS_String tag; + assign_utf8(tag, p, q-p); + return tag; +#endif + } + + /// read attributes and values + void get_attributes(XMLNode::AttributeMap& attributes) const + { + const char* p = _buffer_str.c_str(); + + // find end of tag name + if (*p == '<') + ++p; + + if (*p == '/') + ++p; + else if (*p == '?') + ++p; + + while(isxmlsym(*p)) + ++p; + + // read attributes from buffer + while(*p && *p!='>' && *p!='/') { + while(isspace((unsigned char)*p)) + ++p; + + const char* attr_name = p; + + while(isxmlsym(*p)) + ++p; + + if (*p != '=') + break; //@TODO error handling + + size_t attr_len = p - attr_name; + + if (*++p!='"' && *p!='\'') + break; //@TODO error handling + + char delim = *p; + const char* value = ++p; + + while(*p && *p!=delim) + ++p; + + size_t value_len = p - value; + + if (*p) + ++p; // '"' + +#ifdef XS_STRING_UTF8 + XS_String name_str(attr_name, attr_len); + XS_String value_str(value, value_len); +#else + XS_String name_str, value_str; + assign_utf8(name_str, attr_name, attr_len); + assign_utf8(value_str, value, value_len); +#endif + + attributes[name_str] = DecodeXMLString(value_str); + } + } + +protected: + char* _buffer; + char* _wptr; + size_t _len; + std::string _buffer_str; // UF-8 encoded +}; + +bool XMLReaderBase::parse() +{ + Buffer buffer; + int c = get(); + bool in_comment = false; + + while(c != EOF) { + if (in_comment || c=='<') { + buffer.append(c); + + // read start or end tag + for(;;) { + c = get(); + + if (c == EOF) + break; + + buffer.append(c); + + if (c == '>') + break; + } + + const std::string& b = buffer.str(_utf8); + const char* str = b.c_str(); + + if (in_comment || !strncmp(str+1, "!--", 3)) { + // XML comment + DefaultHandler(b); + + if (strcmp(str+b.length()-3, "-->")) + in_comment = true; + else + in_comment = false; + + c = get(); + } else if (str[1] == '/') { + // end tag + + /*@TODO error handling + const XS_String& tag = buffer.get_tag(); + + if (tag != last_opened_tag) { + ERROR + } + */ + + EndElementHandler(); + + c = get(); + } else if (str[1] == '?') { + // XML declaration + const XS_String& tag = buffer.get_tag(); + + if (tag == "?xml") { + XMLNode::AttributeMap attributes; + buffer.get_attributes(attributes); + + const std::string& version = attributes.get("version"); + const std::string& encoding = attributes.get("encoding"); + + int standalone; + XMLNode::AttributeMap::const_iterator found = // const_cast for ISO C++ compatibility error of GCC + const_cast(attributes).find("standalone"); + if (found != attributes.end()) + standalone = !XS_icmp(found->second.c_str(), XS_TEXT("yes")); + else + standalone = -1; + + XmlDeclHandler(version.empty()?NULL:version.c_str(), encoding.empty()?NULL:encoding.c_str(), standalone); + + if (!encoding.empty() && !_stricmp(encoding.c_str(), "utf-8")) + _utf8 = true; + + c = eat_endl(); + } else if (tag == "?xml-stylesheet") { + XMLNode::AttributeMap attributes; + buffer.get_attributes(attributes); + + StyleSheet stylesheet(attributes.get("href"), attributes.get("type"), !XS_icmp(attributes.get("alternate"), XS_TEXT("yes"))); + stylesheet._title = attributes.get("title"); + stylesheet._media = attributes.get("media"); + stylesheet._charset = attributes.get("charset"); + + _format._stylesheets.push_back(stylesheet); + + c = eat_endl(); + } else { + DefaultHandler(b); + c = get(); + } + } else if (str[1] == '!') { + if (!strncmp(str+2, "DOCTYPE ", 8)) { + _format._doctype.parse(str+10); + + c = eat_endl(); + } else if (!strncmp(str+2, "[CDATA[", 7)) { + // parse strings + while(!buffer.has_CDEnd()) { + c = get(); + + if (c == EOF) + break; + + buffer.append(c); + } + + DefaultHandler(buffer.str(_utf8)); + + c = get(); + } + } else { + // start tag + const XS_String& tag = buffer.get_tag(); + + if (!tag.empty()) { + XMLNode::AttributeMap attributes; + buffer.get_attributes(attributes); + + StartElementHandler(tag, attributes); + + if (str[b.length()-2] == '/') + EndElementHandler(); + } + + c = get(); + } + } else { + buffer.append(c); + + // read white space + for(;;) { + // check for the encoding of the first line end + if (!_endl_defined) + if (c == '\n') { + _format._endl = "\n"; + _endl_defined = true; + } else if (c == '\r') { + _format._endl = "\r\n"; + _endl_defined = true; + } + + c = get(); + + if (c == EOF) + break; + + if (c == '<') + break; + + buffer.append(c); + } + + DefaultHandler(buffer.str(_utf8)); + } + + buffer.reset(); + } + + return true; +} + +int XMLReaderBase::eat_endl() +{ + int c = get(); + + if (c == '\r') + c = get(); + + if (c == '\n') + c = get(); + + return c; +} + + /// return current parser position as string +std::string XMLReaderBase::get_position() const +{ +/*@TODO display parser position in case of errors + int line = XML_GetCurrentLineNumber(_parser); + int column = XML_GetCurrentColumnNumber(_parser); + + std::ostringstream out; + out << "(" << line << ") : [column " << column << "]"; + + return out.str(); +*/ + return ""; +} + + +#ifdef XMLNODE_LOCATION + +XMLLocation XMLReaderBase::get_location() const +{ + return XMLLocation(); //@TODO XMLLocation for XS-native +} + +std::string XMLLocation::str() const +{ + return ""; //TODO +} + +#endif + + + /// store content, white space and comments +void XMLReaderBase::DefaultHandler(const std::string& s) +{ + _content.append(s); +} + + +} // namespace XMLStorage + +#endif // !defined(XS_USE_EXPAT) && !defined(XS_USE_XERCES)