diff --git a/reactos/base/shell/explorer/Jamfile b/reactos/base/shell/explorer/Jamfile index 0938167f781..afa0e4d06db 100644 --- a/reactos/base/shell/explorer/Jamfile +++ b/reactos/base/shell/explorer/Jamfile @@ -7,8 +7,6 @@ import rc-mingw ; -EXPAT_INC = [ modules.peek : EXPAT_INC ] ; - exe explorer : explorer.cpp explorer_intres.rc @@ -44,7 +42,7 @@ exe explorer : dialogs/settings.cpp i386-stub-win32.c : WIN32 _WIN32_IE=0x0600 _WIN32_WINNT=0x0501 WINVER=0x0500 - . $(EXPAT_INC) + . # only for GCC: -fexceptions -Wall -Wno-unused-value gdi32 ole32 @@ -53,8 +51,6 @@ exe explorer : wsock32 oleaut32 msimg32 -# expat notifyhook.dll - libexpat.dll ; diff --git a/reactos/base/shell/explorer/Make-rosshell-MinGW b/reactos/base/shell/explorer/Make-rosshell-MinGW index 0507719ca8a..a092c7bc174 100644 --- a/reactos/base/shell/explorer/Make-rosshell-MinGW +++ b/reactos/base/shell/explorer/Make-rosshell-MinGW @@ -10,7 +10,7 @@ CC = gcc CXX = g++ LINK = g++ -CFLAGS = -DWIN32 -DROSSHELL -D_WIN32_IE=0x0600 -D_WIN32_WINNT=0x0501 -DWINVER=0x0500 -fexceptions -Wall -I. -I$(EXPAT_INC) +CFLAGS = -DWIN32 -DROSSHELL -D_WIN32_IE=0x0600 -D_WIN32_WINNT=0x0501 -DWINVER=0x0500 -fexceptions -Wall -I. RCFLAGS = -DWIN32 -DROSSHELL -D__WINDRES__ LFLAGS = -Wl,--subsystem,windows @@ -68,7 +68,8 @@ OBJECTS = \ searchprogram.o \ settings.o \ i386-stub-win32.o \ - xmlstorage.o + xmlstorage.o \ + xs-native.o LIBS = gdi32 comctl32 msimg32 ole32 uuid DELAYIMPORTS = oleaut32 wsock32 @@ -78,7 +79,7 @@ all: precomp.h.gch $(TARGET) precomp.h.gch: *.h utility/*.h shell/*.h desktop/*.h $(CXX) $(CFLAGS) precomp.h -$(TARGET): $(OBJECTS) $(PROGRAM)$(RES_SUFFIX) notifyhook.dll libexpat.dll +$(TARGET): $(OBJECTS) $(PROGRAM)$(RES_SUFFIX) notifyhook.dll $(LINK) $(LFLAGS) -o $@ $^ $(addprefix -l,$(LIBS)) $(addprefix -l,$(DELAYIMPORTS)) $(PROGRAM)$(RES_SUFFIX): explorer_intres.rc res/*.bmp res/*.ico diff --git a/reactos/base/shell/explorer/Make-rosshell.mak b/reactos/base/shell/explorer/Make-rosshell.mak index fa428b1acc1..48cd7bbf980 100644 --- a/reactos/base/shell/explorer/Make-rosshell.mak +++ b/reactos/base/shell/explorer/Make-rosshell.mak @@ -17,15 +17,14 @@ TARGET_INSTALLDIR := . TARGET_CFLAGS := \ -D__USE_W32API -DWIN32 -D_ROS_ \ -D_WIN32_IE=0x0600 -D_WIN32_WINNT=0x0501 -DWINVER=0x0500 \ - -DUNICODE -fexceptions -Wall -g \ - -I../../../include/expat + -DUNICODE -fexceptions -Wall -g TARGET_CPPFLAGS := $(TARGET_CFLAGS) TARGET_RCFLAGS := -D__USE_W32API -DWIN32 -D_ROS_ -D__WINDRES__ TARGET_SDKLIBS := \ - gdi32.a user32.a comctl32.a ole32.a oleaut32.a shell32.a expat.a \ + gdi32.a user32.a comctl32.a ole32.a oleaut32.a shell32.a \ notifyhook.a ws2_32.a msimg32.a TARGET_GCCLIBS := stdc++ uuid @@ -53,7 +52,8 @@ TARGET_OBJECTS := \ utility/window.o \ utility/dragdropimpl.o \ utility/shellbrowserimpl.o \ - utility/xmlstorage.o + utility/xmlstorage.o \ + utility/xs-native.o TARGET_CPPAPP := yes diff --git a/reactos/base/shell/explorer/Makefile-MinGW b/reactos/base/shell/explorer/Makefile-MinGW index 678fe28ae8d..9e597e19074 100644 --- a/reactos/base/shell/explorer/Makefile-MinGW +++ b/reactos/base/shell/explorer/Makefile-MinGW @@ -9,7 +9,7 @@ CXX = g++ LINK = g++ # -D_NO_ALPHABLEND for builds without msimg32.dll dependency -CFLAGS = -DWIN32 -D_WIN32_IE=0x0600 -D_WIN32_WINNT=0x0501 -DWINVER=0x0500 -fexceptions -Wall -I. -I$(EXPAT_INC) +CFLAGS = -DWIN32 -D_WIN32_IE=0x0600 -D_WIN32_WINNT=0x0501 -DWINVER=0x0500 -fexceptions -Wall -I. RCFLAGS = -DWIN32 -D__WINDRES__ LFLAGS = -Wl,--subsystem,windows @@ -75,14 +75,15 @@ OBJECTS = \ searchprogram.o \ settings.o \ i386-stub-win32.o \ - xmlstorage.o + xmlstorage.o \ + xs-native.o LIBS = gdi32 comctl32 msimg32 ole32 uuid DELAYIMPORTS = oleaut32 wsock32 all: $(TARGET) -$(TARGET): $(OBJECTS) $(PROGRAM)$(RES_SUFFIX) notifyhook.dll libexpat.dll +$(TARGET): $(OBJECTS) $(PROGRAM)$(RES_SUFFIX) notifyhook.dll $(LINK) $(LFLAGS) -o $@ $^ $(addprefix -l,$(LIBS)) $(addprefix -l,$(DELAYIMPORTS)) $(PROGRAM)$(RES_SUFFIX): $(PROGRAM)_intres.rc res/*.bmp res/*.ico diff --git a/reactos/base/shell/explorer/Makefile-Wine b/reactos/base/shell/explorer/Makefile-Wine index c4d51b3f6e0..c3f9ba12857 100644 --- a/reactos/base/shell/explorer/Makefile-Wine +++ b/reactos/base/shell/explorer/Makefile-Wine @@ -6,7 +6,7 @@ MODULE = explorer.exe APPMODE = gui IMPORTS = shell32 comctl32 msimg32 ole32 user32 gdi32 kernel32 advapi32 oleaut32 EXTRADEFS = -D__WINE__ -D_WIN32_IE=0x0600 -D_WIN32_WINNT=0x0501 -DWINVER=0x0500 -D__MINGW32__ -DCINTERFACE -EXTRA_OBJS = notifyhook.dll libexpat.dll +EXTRA_OBJS = notifyhook.dll EXTRALIBS = $(LIBUUID) C_SRCS = \ @@ -22,6 +22,8 @@ CPP_SRCS = \ utility/dragdropimpl.cpp \ utility/shellbrowserimpl.cpp \ utility/xmlstorage.cpp \ + utility/xmlstorage.cpp \ + utility/xs-native.cpp shell/entries.cpp \ shell/winfs.cpp \ shell/unixfs.cpp \ diff --git a/reactos/base/shell/explorer/Makefile-precomp b/reactos/base/shell/explorer/Makefile-precomp index 8945ea402da..c9ae6e42645 100644 --- a/reactos/base/shell/explorer/Makefile-precomp +++ b/reactos/base/shell/explorer/Makefile-precomp @@ -10,7 +10,7 @@ CC = gcc CXX = g++ LINK = g++ -CFLAGS = -DWIN32 -D_WIN32_IE=0x0600 -D_WIN32_WINNT=0x0501 -DWINVER=0x0500 -fexceptions -Wall -I. -I$(EXPAT_INC) +CFLAGS = -DWIN32 -D_WIN32_IE=0x0600 -D_WIN32_WINNT=0x0501 -DWINVER=0x0500 -fexceptions -Wall -I. RCFLAGS = -DWIN32 -D__WINDRES__ LFLAGS = -Wl,--subsystem,windows @@ -76,7 +76,8 @@ OBJECTS = \ searchprogram.o \ settings.o \ i386-stub-win32.o \ - xmlstorage.o + xmlstorage.o \ + xs-native.o LIBS = gdi32 comctl32 msimg32 ole32 uuid DELAYIMPORTS = oleaut32 wsock32 @@ -86,7 +87,7 @@ all: precomp.h.gch $(TARGET) precomp.h.gch: *.h utility/*.h shell/*.h desktop/*.h $(CXX) $(CFLAGS) precomp.h -$(TARGET): $(OBJECTS) $(PROGRAM)$(RES_SUFFIX) notifyhook.dll libexpat.dll +$(TARGET): $(OBJECTS) $(PROGRAM)$(RES_SUFFIX) notifyhook.dll $(LINK) $(LFLAGS) -o $@ $^ $(addprefix -l,$(LIBS)) $(addprefix -l,$(DELAYIMPORTS)) $(PROGRAM)$(RES_SUFFIX): explorer_intres.rc res/*.bmp res/*.ico diff --git a/reactos/base/shell/explorer/expat-license.txt b/reactos/base/shell/explorer/expat-license.txt deleted file mode 100644 index 5c5d524a1f8..00000000000 --- a/reactos/base/shell/explorer/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/shell/explorer/explorer.cpp b/reactos/base/shell/explorer/explorer.cpp index 8cb90757960..2750513617a 100644 --- a/reactos/base/shell/explorer/explorer.cpp +++ b/reactos/base/shell/explorer/explorer.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2003, 2004, 2005 Martin Fuchs + * Copyright 2003, 2004, 2005, 2006 Martin Fuchs * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -94,9 +94,9 @@ void ExplorerGlobals::read_persistent() _cfg_path.printf(TEXT("%s\\ros-explorer-cfg.xml"), _cfg_dir.c_str()); if (!_cfg.read(_cfg_path)) { - if (_cfg._last_error != XML_ERROR_NO_ELEMENTS) - MessageBox(_hwndDesktop, String(_cfg._last_error_msg.c_str()), - TEXT("ROS Explorer - reading user settings"), MB_OK); + //if (_cfg._last_error != XML_ERROR_NO_ELEMENTS) + MessageBox(_hwndDesktop, _cfg._errors.str(), + TEXT("ROS Explorer - reading user settings"), MB_OK); _cfg.read(TEXT("explorer-cfg-template.xml")); } diff --git a/reactos/base/shell/explorer/explorer.dsp b/reactos/base/shell/explorer/explorer.dsp index 283e5a36c72..6a1745b1397 100644 --- a/reactos/base/shell/explorer/explorer.dsp +++ b/reactos/base/shell/explorer/explorer.dsp @@ -310,6 +310,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/shell/explorer/explorer.rbuild b/reactos/base/shell/explorer/explorer.rbuild index f7c8d15f907..87bd4817196 100644 --- a/reactos/base/shell/explorer/explorer.rbuild +++ b/reactos/base/shell/explorer/explorer.rbuild @@ -22,7 +22,6 @@ ole32 oleaut32 shell32 - expat notifyhook precomp.h @@ -65,6 +64,7 @@ dragdropimpl.cpp shellbrowserimpl.cpp xmlstorage.cpp + xs-native.cpp explorer.cpp i386-stub-win32.c diff --git a/reactos/base/shell/explorer/make_explorer.dsp b/reactos/base/shell/explorer/make_explorer.dsp index ccab9f8cac7..d620c8892df 100644 --- a/reactos/base/shell/explorer/make_explorer.dsp +++ b/reactos/base/shell/explorer/make_explorer.dsp @@ -45,7 +45,7 @@ CFG=make_explorer - 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.exe -f Makefile-precomp UNICODE=0" # PROP Rebuild_Opt "clean all" # PROP Target_File "explorer.exe" # PROP Bsc_Name "" @@ -66,7 +66,7 @@ CFG=make_explorer - 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.exe -f Makefile-precomp UNICODE=0 DEBUG=1" # PROP Rebuild_Opt "clean all" # PROP Target_File "explorer.exe" # PROP Bsc_Name "msdevfilt -gcc -pipe "perl d:\tools\gSTLFilt.pl" make -f Makefile.MinGW UNICODE=0 DEBUG=1" @@ -87,7 +87,7 @@ CFG=make_explorer - 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.exe -f Makefile.MinGW UNICODE=1 DEBUG=1" # PROP Rebuild_Opt "clean all" # PROP Target_File "explorer.exe" # PROP Bsc_Name "" @@ -108,7 +108,7 @@ CFG=make_explorer - 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.exe -f Makefile-precomp UNICODE=1" # PROP Rebuild_Opt "clean all" # PROP Target_File "explorer.exe" # PROP Bsc_Name "" diff --git a/reactos/base/shell/explorer/taskbar/favorites.cpp b/reactos/base/shell/explorer/taskbar/favorites.cpp index ea35c4a42f0..579db029bb7 100644 --- a/reactos/base/shell/explorer/taskbar/favorites.cpp +++ b/reactos/base/shell/explorer/taskbar/favorites.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2004 Martin Fuchs + * Copyright 2004, 2006 Martin Fuchs * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -426,12 +426,10 @@ bool Favorites::read(LPCTSTR path) { XMLDoc xbel; - if (!xbel.read(path)) - if (xbel._last_error == XML_ERROR_NO_ELEMENTS) - return false; - else - MessageBox(g_Globals._hwndDesktop, String(xbel._last_error_msg.c_str()), - TEXT("ROS Explorer - reading bookmark file"), MB_OK); + if (!xbel.read(path)) { + MessageBox(g_Globals._hwndDesktop, xbel._errors.str(), + TEXT("ROS Explorer - reading bookmark file"), MB_OK); + } const_XMLPos pos(&xbel); @@ -455,9 +453,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/shell/explorer/taskbar/startmenu.cpp b/reactos/base/shell/explorer/taskbar/startmenu.cpp index 2472dcc354f..d44db044dd5 100644 --- a/reactos/base/shell/explorer/taskbar/startmenu.cpp +++ b/reactos/base/shell/explorer/taskbar/startmenu.cpp @@ -416,7 +416,7 @@ LRESULT StartMenu::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) int new_id = ButtonHitTest(pt); - if (new_id > 0 && new_id != _selected_id) + if (new_id>0 && new_id!=_selected_id) SelectButton(new_id); _last_mouse_pos = lparam; @@ -707,13 +707,13 @@ bool StartMenu::Navigate(int step) for(;;) { idx += step; - if ((int)_buttons.size() <= 1 && (idx<0 || idx>(int)_buttons.size())) + if (_buttons.size()<=1 && (idx<0 || idx>(int)_buttons.size())) break; - if (idx<0) + if (idx < 0) idx += _buttons.size(); - if (idx>(int)_buttons.size()) + if (idx > (int)_buttons.size()) idx -= _buttons.size()+1; if (SelectButtonIndex(idx, false)) diff --git a/reactos/base/shell/explorer/utility/xmlstorage.cpp b/reactos/base/shell/explorer/utility/xmlstorage.cpp index 77f08ba09d9..7ebfdae8b89 100644 --- a/reactos/base/shell/explorer/utility/xmlstorage.cpp +++ b/reactos/base/shell/explorer/utility/xmlstorage.cpp @@ -36,8 +36,8 @@ */ -#ifndef _NO_COMMENT -#define _NO_COMMENT // no #pragma comment(lib, ...) statements in .lib files +#ifndef XS_NO_COMMENT +#define XS_NO_COMMENT // no #pragma comment(lib, ...) statements in .lib files #endif //#include "xmlstorage.h" @@ -46,6 +46,7 @@ // work around GCC's wide string constant bug #ifdef __GNUC__ +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; @@ -57,7 +58,7 @@ namespace XMLStorage { /// remove escape characters from zero terminated string -static std::string unescape(const char* s, char b='"', char e='"') +static std::string unescape(const char* s, char b, char e) { const char* end = s + strlen(s); @@ -74,8 +75,13 @@ static std::string unescape(const char* s, char b='"', char e='"') return std::string(s, end-s); } +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, int l, char b='"', char e='"') +static std::string unescape(const char* s, size_t l, char b, char e) { const char* end = s + l; @@ -92,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) @@ -205,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; @@ -270,46 +281,106 @@ XMLNode* XMLNode::create_relative(const char* path) std::string EncodeXMLString(const XS_String& str) { LPCXSSTR s = str.c_str(); - LPXSSTR buffer = (LPXSSTR)alloca(6*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: - 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; - } + 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 @@ -338,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; @@ -367,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; @@ -378,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--; ) @@ -413,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; @@ -421,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--; ) @@ -435,181 +536,150 @@ void XMLNode::smart_write_worker(std::ostream& out, int indent) const } if (_trailing.empty()) - out << '\n'; + out << format._endl; else out << _trailing; } - /// read XML stream into XML tree below _pos -XML_Status XMLReaderBase::read() +std::ostream& operator<<(std::ostream& out, const XMLError& err) { - XML_Status status = XML_STATUS_OK; + out << err._systemId << "(" << err._line << ") [column " << err._column << "] : " + << err._message; - do { - char* buffer = (char*) XML_GetBuffer(_parser, BUFFER_LEN); - - size_t l = read_buffer(buffer, BUFFER_LEN); - if ((int)l < 0) - break; - - status = XML_ParseBuffer(_parser, l, false); - } while(status == XML_STATUS_OK); - - if (status != XML_STATUS_ERROR) - status = XML_ParseBuffer(_parser, 0, true); - - finish_read(); - - return status; + return out; } - /// return current parser position as string -std::string XMLReaderBase::get_position() const +void DocType::parse(const char* p) { - int line = XML_GetCurrentLineNumber(_parser); - int column = XML_GetCurrentColumnNumber(_parser); + 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 << "(" << line << ") : [column " << column << "]"; + + out << *this; return out.str(); } -#ifdef XMLNODE_LOCATION - -XMLLocation XMLReaderBase::get_location() const -{ - int line = XML_GetCurrentLineNumber(_parser); - int column = XML_GetCurrentColumnNumber(_parser); - - return XMLLocation(_display_path, line, column); -} - -std::string XMLLocation::str() const + /// return merged error strings +XS_String XMLErrorList::str() const { std::ostringstream out; - if (_pdisplay_path) - out << _pdisplay_path; - - out << "(" << _line << ") : [column " << _column << "]"; - - return out.str(); -} - -#endif - - - /// return current error code from Expat -XML_Error XMLReaderBase::get_error_code() const -{ - return XML_GetErrorCode(_parser); -} - - - /// 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; - - pReader->XmlDeclHandler(version, encoding, standalone); -} - - /// notifications about XML start tag -void XMLCALL XMLReaderBase::XML_StartElementHandler(void* userData, const XML_Char* name, const XML_Char** atts) -{ - XMLReaderBase* pReader = (XMLReaderBase*) userData; - - XMLNode::AttributeMap attributes; - - while(*atts) { - const XML_Char* attr_name = *atts++; - const XML_Char* attr_value = *atts++; - - attributes[String_from_XML_Char(attr_name)] = String_from_XML_Char(attr_value); - } - - pReader->StartElementHandler(String_from_XML_Char(name), attributes); -} - - /// notifications about XML end tag -void XMLCALL XMLReaderBase::XML_EndElementHandler(void* userData, const XML_Char* name) -{ - XMLReaderBase* pReader = (XMLReaderBase*) userData; - - pReader->EndElementHandler(); -} - - /// store content, white space and comments -void XMLCALL XMLReaderBase::XML_DefaultHandler(void* userData, const XML_Char* s, int len) -{ - XMLReaderBase* pReader = (XMLReaderBase*) userData; - - pReader->DefaultHandler(s, len); -} - - - /// return error strings for Expat errors -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; + for(const_iterator it=begin(); it!=end(); ++it) + out << *it << std::endl; return out.str(); } @@ -627,13 +697,15 @@ void XMLReaderBase::finish_read() /// store XML version and encoding into XML reader -void XMLReaderBase::XmlDeclHandler(const XML_Char* version, const XML_Char* encoding, int standalone) +void XMLReaderBase::XmlDeclHandler(const char* version, const char* encoding, int standalone) { if (version) - _xml_version = version; + _format._version = version; if (encoding) - _encoding = encoding; + _format._encoding = encoding; + + _format._standalone = standalone; } @@ -657,7 +729,8 @@ void XMLReaderBase::StartElementHandler(const XS_String& name, const XMLNode::At _pos->_content.append(s, p-s); else if (_last_tag == TAG_END) _pos->_trailing.append(s, p-s); - // else TAG_NONE -> don't store white space in root node + else // TAG_NONE at root node + p = s; } else _pos->_children.back()->_trailing.append(s, p-s); @@ -712,13 +785,20 @@ void XMLReaderBase::EndElementHandler() _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/shell/explorer/utility/xmlstorage.h b/reactos/base/shell/explorer/utility/xmlstorage.h index 1970992c332..0eadea679b1 100644 --- a/reactos/base/shell/explorer/utility/xmlstorage.h +++ b/reactos/base/shell/explorer/utility/xmlstorage.h @@ -48,33 +48,45 @@ #endif -#ifndef _NO_EXPAT +#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 "expat.h" #include -#else - -typedef char XML_Char; - -enum XML_Status { - XML_STATUS_ERROR = 0, - XML_STATUS_OK = 1 -}; - -enum XML_Error { - XML_ERROR_NONE, - XML_ERROR_FAILURE -}; - #endif #ifdef _MSC_VER #pragma warning(disable: 4786) -#ifndef _NO_COMMENT -#ifndef _NO_EXPAT +#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") @@ -84,7 +96,7 @@ enum XML_Error { #endif #endif -#ifndef _STRING_DEFINED // _STRING_DEFINED only allowed if using xmlstorage.cpp embedded in the project +#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") @@ -111,7 +123,7 @@ enum XML_Error { #endif #endif // _STRING_DEFINED -#endif // _NO_COMMENT +#endif // XS_NO_COMMENT #endif // _MSC_VER @@ -150,29 +162,35 @@ namespace XMLStorage { #ifndef XS_String #ifdef XS_STRING_UTF8 -#define XS_CHAR char -#define XS_TEXT(x) x +#define XS_CHAR char +#define XS_TEXT(x) x #define LPXSSTR LPSTR #define LPCXSSTR LPCSTR -#define XS_icmp stricmp -#define XS_nicmp strnicmp -#define XS_toi atoi -#define XS_tod strtod -#define XS_len strlen -#define XS_snprintf snprintf -#define XS_vsnprintf vsnprintf +#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_snprintf _snprintf +#define XS_vsnprintf _vsnprintf +#define XS_strstr strstr #else -#define XS_CHAR TCHAR -#define XS_TEXT(x) TEXT(x) +#define XS_CHAR TCHAR +#define XS_TEXT(x) TEXT(x) #define LPXSSTR LPTSTR #define LPCXSSTR LPCTSTR -#define XS_icmp _tcsicmp -#define XS_nicmp _tcsnicmp -#define XS_toi _ttoi -#define XS_tod _tcstod -#define XS_len _tcslen -#define XS_snprintf _sntprintf -#define XS_vsnprintf _vsntprintf +#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_snprintf _sntprintf +#define XS_vsnprintf _vsntprintf +#define XS_strstr _tcsstr #endif #ifndef COUNTOF @@ -183,9 +201,16 @@ namespace XMLStorage { #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 +#define XS_String String #else // _STRING_DEFINED, !XS_STRING_UTF8 @@ -297,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 = (int)strlen(str); - #ifdef UNICODE LPTSTR buffer = (LPTSTR)alloca(sizeof(TCHAR)*lutf8); int l = MultiByteToWideChar(CP_UTF8, 0, str, lutf8, buffer, lutf8); @@ -317,6 +363,13 @@ inline void assign_utf8(XS_String& s, const char* str) s.assign(buffer, 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 @@ -333,6 +386,21 @@ inline std::string get_utf8(LPCTSTR s, size_t l) 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()); @@ -355,7 +423,7 @@ struct FileHolder { FileHolder(LPCTSTR path, LPCTSTR mode) { -#ifdef __STDC_WANT_SECURE_LIB__ // secure CRT functions using VS 2005 +#ifdef __STDC_WANT_SECURE_LIB__ // secure CRT functions using VS 2005 if (_tfopen_s(&_pfile, path, mode) != 0) _pfile = NULL; #else @@ -400,7 +468,7 @@ struct tofstream : public std::ostream, FileHolder tofstream(LPCTSTR path) : super(&_buf), - FileHolder(path, TEXT("w")), + FileHolder(path, TEXT("wb")), #ifdef __GNUC__ _buf(_pfile, std::ios::out) #else @@ -423,17 +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 strings to XMLStorage internal strings + /// 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) @@ -444,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) @@ -463,6 +533,32 @@ 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 @@ -484,13 +580,105 @@ struct XMLLocation std::string str() const; protected: - const char* _pdisplay_path; // character pointer for fast reference - int _line; - int _column; + 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 { @@ -518,9 +706,30 @@ 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 @@ -631,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 @@ -717,7 +926,7 @@ struct XMLNode : public XS_String 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()); @@ -732,18 +941,16 @@ struct XMLNode : public XS_String const XMLLocation& get_location() const {return _location;} #endif - 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 - }; - /// 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: @@ -751,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; @@ -761,13 +968,13 @@ 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; + XMLLocation _location; #endif XMLNode* get_first_child() const @@ -838,8 +1045,9 @@ protected: 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 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; }; @@ -1371,25 +1579,6 @@ protected: }; -#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_TRUE; -extern const LPCXSSTR XS_FALSE; -extern const LPCXSSTR XS_INTFMT; -extern const LPCXSSTR XS_FLOATFMT; -#else -#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 - - /// type converter for boolean data struct XMLBool { @@ -1650,7 +1839,7 @@ struct XMLString { } - XMLString(LPCXSSTR value, LPCXSSTR def=XS_TEXT("")) + XMLString(LPCXSSTR value, LPCXSSTR def=XS_EMPTY) { if (value && *value) _value = value; @@ -1658,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); @@ -1688,14 +1877,14 @@ private: /// 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()) @@ -1749,68 +1938,151 @@ template<> /// XML reader base class struct XMLReaderBase +#ifdef XS_USE_XERCES + : public HandlerBase +#endif { +#ifdef XS_USE_XERCES + + XMLReaderBase(XMLNode* node, InputSource* source, bool adoptSource=false); + virtual ~XMLReaderBase(); + + 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: + XML_Parser _parser; + + 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), - _parser(XML_ParserCreate(NULL)) + _endl_defined(false), + _utf8(false) { - XML_SetUserData(_parser, this); - XML_SetXmlDeclHandler(_parser, XML_XmlDeclHandler); - XML_SetElementHandler(_parser, XML_StartElementHandler, XML_EndElementHandler); - XML_SetDefaultHandler(_parser, XML_DefaultHandler); - _last_tag = TAG_NONE; } - virtual ~XMLReaderBase() - { - XML_ParserFree(_parser); - } + virtual ~XMLReaderBase(); - XML_Status read(); + bool parse(); - std::string get_position() const; - std::string get_instructions() const {return _instructions;} +#endif - XML_Error get_error_code() const; - std::string get_error_string() const; +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 - virtual int read_buffer(char* buffer, int len) = 0; - protected: XMLPos _pos; - XML_Parser _parser; - std::string _xml_version; - std::string _encoding; - std::string _instructions; - std::string _content; + 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 XML_Char* version, const XML_Char* encoding, int standalone); + 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); - - static void XMLCALL XML_XmlDeclHandler(void* userData, const XML_Char* version, const XML_Char* encoding, int standalone); - 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); +#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) { @@ -1831,91 +2103,93 @@ protected: std::istream& _in; }; +#define XMLReader ExpatXMLReader - /// Management of XML file headers -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, bool pretty=true) const + /// read one character from XML stream + int get() { - out << ""; - - if (pretty) - out << std::endl; - - 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); } - bool read(std::istream& in) +#ifdef XS_USE_XERCES + bool read(LPCTSTR path) { - XMLReader reader(this, in); + XMLReader reader(this, path); - return read(reader); +#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) { #ifdef XMLNODE_LOCATION @@ -1923,29 +2197,28 @@ struct XMLDoc : public XMLNode _display_path = display_path; reader._display_path = _display_path.c_str(); #endif - XML_Status status = reader.read(); - _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; } @@ -1956,26 +2229,25 @@ 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; + std::string _display_path; #endif }; @@ -1989,37 +2261,74 @@ 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) + { + } }; -enum PRETTY_FLAGS { - PRETTY_PLAIN = 0, - PRETTY_LINEFEED = 1, - PRETTY_INDENT = 2 +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, PRETTY_FLAGS pretty=PRETTY_INDENT, const XMLHeader& header=XMLHeader()) + XMLWriter(std::ostream& out, const XMLFormat& format=XMLFormat()) : _pofstream(NULL), _out(out), - _pretty(pretty) + _format(format) { - header.print(_out, false); + format.print_header(_out, false); // _format._endl is printed in write_pre() } - XMLWriter(LPCTSTR path, PRETTY_FLAGS pretty=PRETTY_INDENT, const XMLHeader& header=XMLHeader()) + XMLWriter(LPCTSTR path, const XMLFormat& format=XMLFormat()) : _pofstream(new tofstream(path)), _out(*_pofstream), - _pretty(pretty) + _format(format) { - header.print(_out, false); + format.print_header(_out, false); // _format._endl is printed in write_pre() } ~XMLWriter() { - _out << std::endl; + _out << _format._endl; delete _pofstream; } @@ -2086,14 +2395,14 @@ struct XMLWriter protected: tofstream* _pofstream; std::ostream& _out; - PRETTY_FLAGS _pretty; + const XMLFormat&_format; typedef XMLNode::AttributeMap AttrMap; struct StackEntry { XS_String _node_name; - AttrMap _attributes; - std::string _content; + AttrMap _attributes; + std::string _content; WRITESTATE _state; bool _children; @@ -2113,10 +2422,10 @@ protected: void write_pre(StackEntry& entry) { - if (_pretty >= PRETTY_LINEFEED) - _out << std::endl; + if (_format._pretty >= PRETTY_LINEFEED) + _out << _format._endl; - if (_pretty == PRETTY_INDENT) + if (_format._pretty == PRETTY_INDENT) for(size_t i=_stack.size(); --i>0; ) _out << XML_INDENT_SPACE; @@ -2144,10 +2453,10 @@ protected: _out << entry._content; //entry._state = CONTENT; - if (_pretty>=PRETTY_LINEFEED && entry._content.empty()) - _out << std::endl; + if (_format._pretty>=PRETTY_LINEFEED && entry._content.empty()) + _out << _format._endl; - if (_pretty==PRETTY_INDENT && entry._content.empty()) + if (_format._pretty==PRETTY_INDENT && entry._content.empty()) for(size_t i=_stack.size(); --i>0; ) _out << XML_INDENT_SPACE; diff --git a/reactos/base/shell/explorer/utility/xs-native.cpp b/reactos/base/shell/explorer/utility/xs-native.cpp new file mode 100644 index 00000000000..90f5bea5852 --- /dev/null +++ b/reactos/base/shell/explorer/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)