Commit in reactos/subsys/system/explorer on MAIN
Jamfile+11.13 -> 1.14
Makefile+11.31 -> 1.32
Makefile.MinGW+11.21 -> 1.22
Makefile.Wine+11.11 -> 1.12
doxy-footer.html+1-11.42 -> 1.43
explorer.cpp+17-131.63 -> 1.64
explorer.dsp+81.55 -> 1.56
globals.h+7-21.36 -> 1.37
make_explorer.dsp+1-11.17 -> 1.18
shell/fatfs.cpp+1-11.3 -> 1.4
taskbar/favorites.cpp+292added 1.1
       /favorites.h+87added 1.1
       /startmenu.cpp+1-11.83 -> 1.84
       /traynotify.cpp+4-41.55 -> 1.56
utility/xmlstorage.cpp+126-421.5 -> 1.6
       /xmlstorage.h+380-661.10 -> 1.11
+929-131
2 added + 14 modified, total 16 files
import IE bookmarks and convert into XBEL format bookmark file

reactos/subsys/system/explorer
Jamfile 1.13 -> 1.14
diff -u -r1.13 -r1.14
--- Jamfile	27 Mar 2004 14:02:27 -0000	1.13
+++ Jamfile	4 Apr 2004 16:04:33 -0000	1.14
@@ -31,6 +31,7 @@
 	taskbar/startmenu.cpp
 	taskbar/taskbar.cpp
 	taskbar/traynotify.cpp
+	taskbar/favorites.cpp
 	desktop/desktop.cpp
 #	utility/splitpath.c
 	utility/dragdropimpl.cpp

reactos/subsys/system/explorer
Makefile 1.31 -> 1.32
diff -u -r1.31 -r1.32
--- Makefile	24 Mar 2004 10:34:21 -0000	1.31
+++ Makefile	4 Apr 2004 16:04:33 -0000	1.32
@@ -99,6 +99,7 @@
 	startmenu.o \
 	traynotify.o \
 	quicklaunch.o \
+	favorites.o \
 	searchprogram.o \
 	settings.o \
 	i386-stub-win32.o \

reactos/subsys/system/explorer
Makefile.MinGW 1.21 -> 1.22
diff -u -r1.21 -r1.22
--- Makefile.MinGW	27 Mar 2004 14:02:27 -0000	1.21
+++ Makefile.MinGW	4 Apr 2004 16:04:33 -0000	1.22
@@ -68,6 +68,7 @@
 	startmenu.o \
 	traynotify.o \
 	quicklaunch.o \
+	favorites.o \
 	searchprogram.o \
 	settings.o \
 	i386-stub-win32.o \

reactos/subsys/system/explorer
Makefile.Wine 1.11 -> 1.12
diff -u -r1.11 -r1.12
--- Makefile.Wine	21 Mar 2004 23:36:23 -0000	1.11
+++ Makefile.Wine	4 Apr 2004 16:04:33 -0000	1.12
@@ -39,6 +39,7 @@
 	taskbar/startmenu.cpp \
 	taskbar/traynotify.cpp \
 	taskbar/quicklaunch.cpp \
+	taskbar/favorites.cpp \
 	dialogs/searchprogram.cpp \
 	dialogs/settings.cpp
 

reactos/subsys/system/explorer
doxy-footer.html 1.42 -> 1.43
diff -u -r1.42 -r1.43
--- doxy-footer.html	28 Mar 2004 12:00:45 -0000	1.42
+++ doxy-footer.html	4 Apr 2004 16:04:33 -0000	1.43
@@ -3,7 +3,7 @@
   <tr>
     <td><address style="align: right;"><small>
 ROS Explorer Source Code Documentation
-<br>generated on 28.03.2004 by <a href="http://www.doxygen.org/index.html">
+<br>generated on 04.04.2004 by <a href="http://www.doxygen.org/index.html">
 <img src="doxygen.png" alt="doxygen" align="middle" border=0>
 	</small></address>
 	</td>

reactos/subsys/system/explorer
explorer.cpp 1.63 -> 1.64
diff -u -r1.63 -r1.64
--- explorer.cpp	28 Mar 2004 14:55:17 -0000	1.63
+++ explorer.cpp	4 Apr 2004 16:04:33 -0000	1.64
@@ -82,27 +82,31 @@
 }
 
 
-bool ExplorerGlobals::read_cfg()
+void ExplorerGlobals::read_persistent()
 {
 	 // read configuration file
 	_cfg_dir.printf(TEXT("%s\\ReactOS"), (LPCTSTR)SpecialFolderFSPath(CSIDL_APPDATA,0));
-	_cfg_path.printf(TEXT("%s\\ros-explorer.xml"), _cfg_dir.c_str());
+	_cfg_path.printf(TEXT("%s\\ros-explorer-cfg.xml"), _cfg_dir.c_str());
 
-	if (_cfg.read(_cfg_path))
-		return true;
+	if (!_cfg.read(_cfg_path))
+		_cfg.read(TEXT("explorer-cfg-template.xml"));
 
-	if (_cfg.read("explorer-cfg-template.xml"))
-		return true;
+	 // read bookmarks
+	_favorites_path.printf(TEXT("%s\\ros-explorer-bookmarks.xml"), _cfg_dir.c_str());
 
-	return false;
+	if (!_favorites.read(_favorites_path)) {
+		_favorites.import_IE_favorites(0);
+		_favorites.write(_favorites_path);
+	}
 }
 
-void ExplorerGlobals::write_cfg()
+void ExplorerGlobals::write_persistent()
 {
 	 // write configuration file
 	RecursiveCreateDirectory(_cfg_dir);
 
 	_cfg.write(_cfg_path);
+	_favorites.write(_favorites_path);
 }
 
 
@@ -110,7 +114,7 @@
 {
 	XMLPos pos(&_cfg);
 
-	pos.create("explorer-cfg");
+	pos.smart_create("explorer-cfg");
 
 	return pos;
 }
@@ -119,8 +123,8 @@
 {
 	XMLPos pos(&_cfg);
 
-	pos.create("explorer-cfg");
-	pos.create(name);
+	pos.smart_create("explorer-cfg");
+	pos.smart_create(name);
 
 	return pos;
 }
@@ -790,7 +794,7 @@
 	 // init common controls library
 	CommonControlInit usingCmnCtrl;
 
-	g_Globals.read_cfg();
+	g_Globals.read_persistent();
 
 	if (startup_desktop) {
 		g_Globals._desktops.init();
@@ -818,7 +822,7 @@
 	int ret = explorer_main(hInstance, lpCmdLine, nShowCmd);
 
 	 // write configuration file
-	g_Globals.write_cfg();
+	g_Globals.write_persistent();
 
 	return ret;
 }

reactos/subsys/system/explorer
explorer.dsp 1.55 -> 1.56
diff -u -r1.55 -r1.56
--- explorer.dsp	21 Mar 2004 23:36:23 -0000	1.55
+++ explorer.dsp	4 Apr 2004 16:04:33 -0000	1.56
@@ -554,6 +554,14 @@
 # End Source File
 # Begin Source File
 
+SOURCE=.\taskbar\favorites.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\taskbar\favorites.h
+# End Source File
+# Begin Source File
+
 SOURCE=.\notifyhook\notifyhook.h
 # End Source File
 # Begin Source File

reactos/subsys/system/explorer
globals.h 1.36 -> 1.37
diff -u -r1.36 -r1.37
--- globals.h	28 Mar 2004 14:55:17 -0000	1.36
+++ globals.h	4 Apr 2004 16:04:33 -0000	1.37
@@ -30,6 +30,8 @@
 
 using namespace XMLStorage;
 
+#include "taskbar/favorites.h"
+
 
  /// management of file types
 struct FileTypeInfo {
@@ -228,8 +230,8 @@
 
 	void	init(HINSTANCE hInstance);
 
-	bool	read_cfg();
-	void	write_cfg();
+	void	read_persistent();
+	void	write_persistent();
 
 	XMLPos	get_cfg();
 	XMLPos	get_cfg(const String& name);
@@ -259,6 +261,9 @@
 	XMLDoc		_cfg;
 	String		_cfg_dir;
 	String		_cfg_path;
+
+	Favorites	_favorites;
+	String		_favorites_path;
 } g_Globals;
 
 

reactos/subsys/system/explorer
make_explorer.dsp 1.17 -> 1.18
diff -u -r1.17 -r1.18
--- make_explorer.dsp	28 Mar 2004 09:34:42 -0000	1.17
+++ make_explorer.dsp	4 Apr 2004 16:04:33 -0000	1.18
@@ -108,7 +108,7 @@
 # PROP Use_Debug_Libraries 0
 # PROP Output_Dir "URelease"
 # PROP Intermediate_Dir "URelease"
-# PROP Cmd_Line "msdevfilt -gcc make -f Makefile.MinGW UNICODE=1"
+# PROP Cmd_Line "make -f Makefile.MinGW UNICODE=1"
 # PROP Rebuild_Opt "clean all"
 # PROP Target_File "explorer.exe"
 # PROP Bsc_Name ""

reactos/subsys/system/explorer/shell
fatfs.cpp 1.3 -> 1.4
diff -u -r1.3 -r1.4
--- fatfs.cpp	14 Mar 2004 12:06:25 -0000	1.3
+++ fatfs.cpp	4 Apr 2004 16:04:34 -0000	1.4
@@ -460,7 +460,7 @@
 	_CacheDty = NULL;
 	_Caches = 0;
 
-	_hDrive = CreateFile(path, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
+	_hDrive = CreateFile(path, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
 
 	if (_hDrive != INVALID_HANDLE_VALUE) {
 		_boot_sector.BytesPerSector = 512;

reactos/subsys/system/explorer/taskbar
favorites.cpp added at 1.1
diff -N favorites.cpp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ favorites.cpp	4 Apr 2004 16:04:34 -0000	1.1
@@ -0,0 +1,292 @@
+/*
+ * Copyright 2004 Martin Fuchs
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+ //
+ // Explorer and Desktop clone
+ //
+ // favorites.cpp
+ //
+ // Martin Fuchs, 04.04.2004
+ //
+
+
+#include "../utility/utility.h"
+
+#include "../explorer.h"
+#include "../globals.h"
+
+#include "startmenu.h"
+
+
+ /// read .URL file
+bool Bookmark::read_url(LPCTSTR path)
+{
+	char line[BUFFER_LEN];
+
+	tifstream in(path);
+
+	while(in.good()) {
+		in.getline(line, BUFFER_LEN);
+
+		const char* p = line;
+		while(isspace(*p))
+			++p;
+
+		const char* keyword = p;
+		const char* eq = strchr(p, '=');
+
+		if (eq) {
+			const char* cont = eq + 1;
+			while(isspace(*cont))
+				++cont;
+
+			if (!strnicmp(keyword, "URL", 3))
+				_url = cont;
+			else if (!strnicmp(keyword, "IconFile", 8))
+				_icon_path = cont;
+		}
+	}
+
+	return true;
+}
+
+ /// convert XBEL bookmark node
+bool Bookmark::read_xbel(const_XMLPos& pos)
+{
+	_url = pos.get("href");
+
+	if (!pos.go_down("title"))
+		return false;
+
+	_name = pos->get_content();
+
+	pos.back();
+
+	return true;
+}
+
+
+BookmarkNode::BookmarkNode(const Bookmark& bm)
+ :	_type(BMNT_BOOKMARK)
+{
+	_pbookmark = new Bookmark(bm);
+}
+
+BookmarkNode::BookmarkNode(const BookmarkFolder& bmf)
+ :	_type(BMNT_FOLDER)
+{
+	_pfolder = new BookmarkFolder(bmf);
+}
+
+BookmarkNode::BookmarkNode(const BookmarkNode& other)
+ :	_type(other._type)
+{
+	if (_type == BMNT_BOOKMARK)
+		_pbookmark = new Bookmark(*other._pbookmark);
+	else
+		_pfolder = new BookmarkFolder(*other._pfolder);
+}
+
+BookmarkNode::~BookmarkNode()
+{
+	if (_type == BMNT_BOOKMARK)
+		delete _pbookmark;
+	else
+		delete _pfolder;
+}
+
+
+ /// read bookmark list from XBEL formated XML tree
+void BookmarkList::read(const_XMLPos& pos)
+{
+	const XMLNode::Children& children = pos->get_children();
+
+	for(XMLNode::Children::const_iterator it=children.begin(); it!=children.end(); ++it) {
+		const XMLNode& node = **it;
+		const_XMLPos sub_pos(&node);
+
+		if (node == "folder") {
+			BookmarkFolder new_folder;
+
+			if (sub_pos.go_down("title")) {
+				new_folder._name = sub_pos->get_content();
+				sub_pos.back();
+			}
+
+			new_folder._bookmarks.read(sub_pos);
+
+			push_back(new_folder);
+		} else if (node == "bookmark") {
+			Bookmark bookmark;
+
+			if (bookmark.read_xbel(sub_pos))
+				push_back(bookmark);
+		}
+	}
+}
+
+ /// write bookmark list into XBEL formated XML tree
+void BookmarkList::write(XMLPos& pos) const
+{
+	for(const_iterator it=begin(); it!=end(); ++it) {
+		const BookmarkNode& node = *it;
+
+		if (node._type == BookmarkNode::BMNT_FOLDER) {
+			BookmarkFolder& folder = *node._pfolder;
+
+			pos.create("folder");
+
+			pos.create("title");
+			pos->set_content(folder._name);
+			pos.back();
+
+			folder._bookmarks.write(pos);
+
+			pos.back();
+		} else {	// node._type == BookmarkNode::BMNT_BOOKMARK
+			Bookmark& bookmark = *node._pbookmark;
+
+			if (!bookmark._url.empty()) {
+				pos.create("bookmark");
+
+				pos["href"] = bookmark._url;
+
+				pos.create("title");
+				pos->set_content(bookmark._name);
+				pos.back();
+
+				pos.back();
+			}
+		}
+	}
+}
+
+
+void BookmarkList::import_IE_favorites(ShellDirectory& dir, HWND hwnd)
+{
+	TCHAR path[MAX_PATH], ext[_MAX_EXT];
+
+	dir.smart_scan(SCAN_FILESYSTEM);
+
+	for(Entry*entry=dir._down; entry; entry=entry->_next) {
+		if (entry->_shell_attribs & SFGAO_HIDDEN)	// hide files like "desktop.ini"
+			continue;
+
+		String name;
+
+		if (entry->_etype == ET_SHELL)
+			name = dir._folder.get_name(static_cast<ShellEntry*>(entry)->_pidl);
+		else
+			name = entry->_display_name;
+
+		if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+			BookmarkFolder new_folder;
+
+			new_folder._name = name;
+
+			if (entry->_etype == ET_SHELL) {
+				ShellDirectory new_dir(dir._folder, static_cast<ShellEntry*>(entry)->_pidl, hwnd);
+				new_folder._bookmarks.import_IE_favorites(new_dir, hwnd);
+			} else {
+				entry->get_path(path);
+				ShellDirectory new_dir(GetDesktopFolder(), path, hwnd);
+				new_folder._bookmarks.import_IE_favorites(new_dir, hwnd);
+			}
+
+			push_back(new_folder);
+		} else {
+			Bookmark bookmark;
+
+			bookmark._name = name;
+
+			entry->get_path(path);
+			_tsplitpath(path, NULL, NULL, NULL, ext);
+
+			if (!_tcsicmp(ext, TEXT(".url"))) {
+				bookmark.read_url(path);
+				push_back(bookmark);
+			} else {
+				///@todo read shell links
+				assert(0);
+			}
+		}
+	}
+}
+
+
+ /// read XBEL bookmark file
+bool Favorites::read(LPCTSTR path)
+{
+	XMLDoc xbel;
+
+	if (!xbel.read(path))
+		return false;
+
+	const_XMLPos pos(&xbel);
+
+	if (!pos.go_down("xbel"))
+		return false;
+
+	super::read(pos);
+
+	pos.back();
+
+	return true;
+}
+
+ /// write XBEL bookmark file
+void Favorites::write(LPCTSTR path) const
+{
+	XMLDoc xbel;
+
+	XMLPos pos(&xbel);
+	pos.create("xbel");
+	super::write(pos);
+	pos.back();
+
+	xbel.write(path, XMLNode::FORMAT_SMART, XMLHeader("1.0", "UTF-8", "<!DOCTYPE xbel"
+		" PUBLIC \"+//IDN python.org//DTD XML Bookmark Exchange Language 1.0//EN//XML\"\n"
+		" \"http://www.python.org/topics/xml/dtds/xbel-1.0.dtd\">"));
+}
+
+ /// import Internet Explorer bookmarks from Favorites folder
+bool Favorites::import_IE_favorites(HWND hwnd)
+{
+	WaitCursor wait;
+
+	StartMenuShellDirs dirs;
+
+	try {
+		dirs.push_back(ShellDirectory(GetDesktopFolder(), SpecialFolderPath(CSIDL_COMMON_FAVORITES, hwnd), hwnd));
+		dirs.push_back(ShellDirectory(GetDesktopFolder(), SpecialFolderPath(CSIDL_FAVORITES, hwnd), hwnd));
+	} catch(COMException&) {
+	}
+
+	for(StartMenuShellDirs::iterator it=dirs.begin(); it!=dirs.end(); ++it) {
+		StartMenuDirectory& smd = *it;
+		ShellDirectory& dir = smd._dir;
+
+		try {
+			super::import_IE_favorites(dir, hwnd);
+		} catch(COMException&) {
+		}
+	}
+
+	return true;
+}

reactos/subsys/system/explorer/taskbar
favorites.h added at 1.1
diff -N favorites.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ favorites.h	4 Apr 2004 16:04:34 -0000	1.1
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2004 Martin Fuchs
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+ //
+ // Explorer and Desktop clone
+ //
+ // favorites.h
+ //
+ // Martin Fuchs, 04.04.2004
+ //
+
+
+struct Bookmark
+{
+	Bookmark() : _icon_idx(0) {}
+
+	String	_name;
+	String	_url;
+	String	_description;
+	String	_icon_path;
+	int		_icon_idx;
+
+	bool	read_url(LPCTSTR path);
+	bool	read_xbel(const_XMLPos& pos);
+};
+
+struct BookmarkFolder;
+
+struct BookmarkNode
+{
+	BookmarkNode(const Bookmark& bm);
+	BookmarkNode(const BookmarkFolder& bmf);
+	BookmarkNode(const BookmarkNode& other);
+	~BookmarkNode();
+
+	enum BOOKMARKNODE_TYPE {
+		BMNT_BOOKMARK, BMNT_FOLDER
+	};
+
+	BOOKMARKNODE_TYPE	_type;
+
+	union {
+		Bookmark*	_pbookmark;
+		BookmarkFolder* _pfolder;
+	};
+};
+
+struct BookmarkList : public list<BookmarkNode>
+{
+	void	import_IE_favorites(struct ShellDirectory& dir, HWND hwnd);
+
+	void	read(const_XMLPos& pos);
+	void	write(XMLPos& pos) const;
+};
+
+struct BookmarkFolder
+{
+	String	_name;
+	String	_description;
+	BookmarkList _bookmarks;
+};
+
+struct Favorites : public BookmarkList
+{
+	typedef BookmarkList super;
+
+	bool	read(LPCTSTR path);
+	void	write(LPCTSTR path) const;
+
+	bool	import_IE_favorites(HWND hwnd);
+};

reactos/subsys/system/explorer/taskbar
startmenu.cpp 1.83 -> 1.84
diff -u -r1.83 -r1.84
--- startmenu.cpp	20 Mar 2004 13:49:12 -0000	1.83
+++ startmenu.cpp	4 Apr 2004 16:04:34 -0000	1.84
@@ -1616,7 +1616,7 @@
 		break;
 
 	  case IDC_FAVORITES:
-		CreateSubmenu(id, CSIDL_FAVORITES, ResString(IDS_FAVORITES));
+		CreateSubmenu(id, CSIDL_COMMON_FAVORITES, CSIDL_FAVORITES, ResString(IDS_FAVORITES));
 		break;
 
 	  case IDC_BROWSE:

reactos/subsys/system/explorer/taskbar
traynotify.cpp 1.55 -> 1.56
diff -u -r1.55 -r1.56
--- traynotify.cpp	28 Mar 2004 22:17:48 -0000	1.55
+++ traynotify.cpp	4 Apr 2004 16:04:34 -0000	1.56
@@ -259,11 +259,11 @@
 	 // write notification icon settings to XML configuration file
 	XMLPos pos = g_Globals.get_cfg();
 
-	pos.create("desktopbar");
+	pos.smart_create("desktopbar");
 	XMLBoolRef(pos, "options", "show-clock") = _hwndClock!=0;
 	pos.back();
 
-	pos.create("notify-icons");
+	pos.smart_create("notify-icons");
 
 	XMLBoolRef(pos, "options", "hide-inactive") = _hide_inactive;
 	XMLBoolRef(pos, "options", "show-hidden") = _show_hidden;
@@ -272,7 +272,7 @@
 		NotifyIconConfig& cfg = *it;
 
 		 // search for the corresponding node using the original name
-		pos.create("icon", "name", cfg._name);
+		pos.smart_create("icon", "name", cfg._name);
 
 		 // refresh unique name
 		cfg.create_name();
@@ -293,7 +293,7 @@
 
 	if (vis != flag) {
 		if (flag) {
-			 // create clock window
+			 // smart_create clock window
 			_hwndClock = ClockWindow::Create(_hwnd);
 
 			if (_hwndClock) {

reactos/subsys/system/explorer/utility
xmlstorage.cpp 1.5 -> 1.6
diff -u -r1.5 -r1.6
--- xmlstorage.cpp	28 Mar 2004 12:00:46 -0000	1.5
+++ xmlstorage.cpp	4 Apr 2004 16:04:34 -0000	1.6
@@ -54,6 +54,34 @@
 }
 
 
+ /// read XML stream into XML tree below _pos
+XML_Status XMLReader::read(std::istream& in)
+{
+	XML_Status status = XML_STATUS_OK;
+
+	while(in.good() && status==XML_STATUS_OK) {
+		char* buffer = (char*) XML_GetBuffer(_parser, BUFFER_LEN);
+
+		in.read(buffer, BUFFER_LEN);
+
+		status = XML_ParseBuffer(_parser, in.gcount(), false);
+	}
+
+	if (status != XML_STATUS_ERROR)
+		status = XML_ParseBuffer(_parser, 0, true);
+
+/*
+	if (status == XML_STATUS_ERROR)
+		cerr << get_error_string();
+*/
+
+	_pos->append_trailing(_content.c_str(), _content.length());
+	_content.erase();
+
+	return status;
+}
+
+
  /// store XML version and encoding into XML reader
 void XMLCALL XMLReader::XML_XmlDeclHandler(void* userData, const XML_Char* version, const XML_Char* encoding, int standalone)
 {
@@ -65,12 +93,31 @@
 	}
 }
 
- /// notifications about XML tag start
+ /// notifications about XML start tag
 void XMLCALL XMLReader::XML_StartElementHandler(void* userData, const XML_Char* name, const XML_Char** atts)
 {
 	XMLReader* pThis = (XMLReader*) userData;
 
-	XMLNode* node = new XMLNode(String_from_XML_Char(name));
+	 // search for end of first line
+	const char* s = pThis->_content.c_str();
+	const char* p = s;
+	const char* e = p + pThis->_content.length();
+
+	for(; p<e; ++p)
+		if (*p == '\n') {
+			++p;
+			break;
+		}
+
+	if (p != s)
+		pThis->_pos->append_trailing(s, p-s);
+
+	std::string leading;
+
+	if (p != e)
+		leading.assign(p, e-p);
+
+	XMLNode* node = new XMLNode(String_from_XML_Char(name), leading);
 
 	pThis->_pos.add_down(node);
 
@@ -81,17 +128,41 @@
 		(*node)[String_from_XML_Char(attr_name)] = String_from_XML_Char(attr_value);
 	}
 
-	pThis->_in_tag = true;
+	pThis->_in_node = true;
+	pThis->_content.erase();
 }
 
- /// notifications about XML tag end
+ /// notifications about XML end tag
 void XMLCALL XMLReader::XML_EndElementHandler(void* userData, const XML_Char* name)
 {
 	XMLReader* pThis = (XMLReader*) userData;
 
+	 // search for end of first line
+	const char* s = pThis->_content.c_str();
+	const char* p = s;
+	const char* e = p + pThis->_content.length();
+
+	for(; p<e; ++p)
+		if (*p == '\n') {
+			++p;
+			break;
+		}
+
+	if (p != s)
+		pThis->_pos->append_content(s, p-s);
+
+	std::string leading;
+
+	if (p != e)
+		leading.assign(p, e-p);
+
+	if (leading.empty())
+		pThis->_pos->_end_leading = leading;
+
 	pThis->_pos.back();
 
-	pThis->_in_tag = false;
+	pThis->_in_node = false;
+	pThis->_content.erase();
 }
 
  /// store content, white space and comments
@@ -99,14 +170,11 @@
 {
 	XMLReader* pThis = (XMLReader*) userData;
 
-	if (pThis->_in_tag)
-		pThis->_pos->append_content(s, len);
-	else
-		pThis->_pos->append_trailing(s, len);
+	pThis->_content.append(s, len);
 }
 
 
-std::string XMLString(LPCTSTR s)
+std::string EncodeXMLString(LPCTSTR s)
 {
 	TCHAR buffer[BUFFER_LEN];
 	LPTSTR o = buffer;
@@ -132,22 +200,46 @@
 	return get_utf8(buffer, o-buffer);
 }
 
+String DecodeXMLString(LPCTSTR s)
+{
+	TCHAR buffer[BUFFER_LEN];
+	LPTSTR o = buffer;
+
+	for(LPCTSTR p=s; *p; ++p)
+		if (*p == '&') {
+			if (!_tcsnicmp(p+1, TEXT("amp;"), 4)) {
+				*o++ = '&';
+				p += 4;
+			} else if (!_tcsnicmp(p+1, TEXT("lt;"), 3)) {
+				*o++ = '<';
+				p += 3;
+			} else if (!_tcsnicmp(p+1, TEXT("gt;"), 3)) {
+				*o++ = '>';
+				p += 3;
+			} else
+				*o++ = *p;
+		} else
+			*o++ = *p;
+
+	return String(buffer, o-buffer);
+}
+
 
  /// write node with children tree to output stream using original white space
-void XMLNode::write_worker(std::ostream& out, WRITE_MODE mode, int indent) const
+void XMLNode::write_worker(std::ostream& out, int indent) const
 {
-	out << '<' << XMLString(*this);
+	out << _leading << '<' << EncodeXMLString(*this);
 
 	for(AttributeMap::const_iterator it=_attributes.begin(); it!=_attributes.end(); ++it)
-		out << ' ' << XMLString(it->first) << "=\"" << XMLString(it->second) << "\"";
+		out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\"";
 
 	if (!_children.empty() || !_content.empty()) {
 		out << '>' << _content;
 
 		for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it)
-			(*it)->write_worker(out, mode, indent+1);
+			(*it)->write_worker(out, indent+1);
 
-		out << "</" << XMLString(*this) << '>';
+		out << _end_leading << "</" << EncodeXMLString(*this) << '>';
 	} else
 		out << "/>";
 
@@ -156,81 +248,73 @@
 
 
  /// pretty print node with children tree to output stream
-void XMLNode::pretty_write_worker(std::ostream& out, WRITE_MODE mode, int indent) const
+void XMLNode::pretty_write_worker(std::ostream& out, int indent) const
 {
 	for(int i=indent; i--; )
 		out << XML_INDENT_SPACE;
 
-	out << '<' << XMLString(*this);
+	out << '<' << EncodeXMLString(*this);
 
 	for(AttributeMap::const_iterator it=_attributes.begin(); it!=_attributes.end(); ++it)
-		out << ' ' << XMLString(it->first) << "=\"" << XMLString(it->second) << "\"";
+		out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\"";
 
 	if (!_children.empty() || !_content.empty()) {
 		out << ">\n";
 
 		for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it)
-			(*it)->pretty_write_worker(out, mode, indent+1);
+			(*it)->pretty_write_worker(out, indent+1);
 
 		for(int i=indent; i--; )
 			out << XML_INDENT_SPACE;
 
-		out << "</" << XMLString(*this) << ">\n";
+		out << "</" << EncodeXMLString(*this) << ">\n";
 	} else
 		out << "/>\n";
 }
 
 
-
  /// write node with children tree to output stream using smart formating
-bool XMLNode::smart_write_worker(std::ostream& out, int indent, bool next_format) const
+void XMLNode::smart_write_worker(std::ostream& out, int indent) const
 {
-	bool format_pre, format_mid, format_post;
-
-	format_pre = next_format;
-	format_mid = _content.empty();
-	format_post = _trailing.empty();
-
-	if (format_pre)
+	if (_leading.empty())
 		for(int i=indent; i--; )
 			out << XML_INDENT_SPACE;
+	else
+		out << _leading;
 
-	out << '<' << XMLString(*this);
+	out << '<' << EncodeXMLString(*this);
 
 	for(AttributeMap::const_iterator it=_attributes.begin(); it!=_attributes.end(); ++it)
-		out << ' ' << XMLString(it->first) << "=\"" << XMLString(it->second) << "\"";
+		out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\"";
 
 	if (!_children.empty() || !_content.empty()) {
 		out << '>';
 
-		if (format_mid)
+		if (_content.empty())
 			out << '\n';
 		else
 			out << _content;
 
 		Children::const_iterator it = _children.begin();
 
-		if (it != _children.end()) {
-			next_format = (*it)->_content.empty() && (*it)->_trailing.empty();
-
+		if (it != _children.end())
 			for(; it!=_children.end(); ++it)
-				next_format = (*it)->smart_write_worker(out, indent+1, next_format);
-		}
+				(*it)->smart_write_worker(out, indent+1);
 
-		if (next_format)
+		if (_end_leading.empty())
 			for(int i=indent; i--; )
 				out << XML_INDENT_SPACE;
+		else
+			out << _end_leading;
 
-		out << "</" << XMLString(*this) << '>';
+		out << "</" << EncodeXMLString(*this) << '>';
 	} else
 		out << "/>";
 
-	if (format_post)
+	if (_trailing.empty())
 		out << '\n';
 	else
 		out << _trailing;
-
-	return format_post;
 }
 
 

reactos/subsys/system/explorer/utility
xmlstorage.h 1.10 -> 1.11
diff -u -r1.10 -r1.11
--- xmlstorage.h	28 Mar 2004 22:17:49 -0000	1.10
+++ xmlstorage.h	4 Apr 2004 16:04:34 -0000	1.11
@@ -47,7 +47,7 @@
 #include <windows.h>	// for LPCTSTR
 
 #ifdef UNICODE
-#define	_UNICODE
+#define _UNICODE
 #endif
 #include <tchar.h>
 
@@ -202,11 +202,74 @@
 	return get_utf8(s.c_str(), s.length());
 }
 
-extern std::string XMLString(LPCTSTR s);
+extern std::string EncodeXMLString(LPCTSTR s);
+extern String DecodeXMLString(LPCTSTR s);
+
+
+#ifdef __GNUC__
+#include <ext/stdio_filebuf.h>
+typedef __gnu_cxx::stdio_filebuf<char> STDIO_FILEBUF;
+#else
+typedef std::filebuf STDIO_FILEBUF;
+#endif
+
+struct tifstream : public std::istream
+{
+	typedef std::istream super;
+
+	tifstream(LPCTSTR path)
+	 :	super(&_buf),
+		_pfile(_tfopen(path, TEXT("r"))),
+#ifdef __GNUC__
+		_buf(_pfile, ios::in)
+#else
+		_buf(_pfile)
+#endif
+	{
+	}
+
+	~tifstream()
+	{
+		if (_pfile)
+			fclose(_pfile);
+	}
+
+protected:
+	FILE*	_pfile;
+	STDIO_FILEBUF _buf;
+};
+
+struct tofstream : public std::ostream
+{
+	typedef std::ostream super;
+
+	tofstream(LPCTSTR path)
+	 :	super(&_buf),
+		_pfile(_tfopen(path, TEXT("w"))),
+#ifdef __GNUC__
+		_buf(_pfile, ios::out)
+#else
+		_buf(_pfile)
+#endif
+	{
+	}
+
+	~tofstream()
+	{
+		flush();
+
+		if (_pfile)
+			fclose(_pfile);
+	}
+
+protected:
+	FILE*	_pfile;
+	STDIO_FILEBUF _buf;
+};
 
 
  // write XML files with 2 spaces indenting
-#define	XML_INDENT_SPACE "  "
+#define XML_INDENT_SPACE "  "
 
 
 #ifdef XML_UNICODE	// Are XML_Char strings UTF-16 encoded?
@@ -279,6 +342,7 @@
 
 	 // access to protected class members for XMLPos and XMLReader
 	friend struct XMLPos;
+	friend struct const_XMLPos;
 	friend struct XMLReader;
 
 	XMLNode(const String& name)
@@ -286,9 +350,17 @@
 	{
 	}
 
+	XMLNode(const String& name, const std::string& leading)
+	 :	String(name),
+		_leading(leading)
+	{
+	}
+
 	XMLNode(const XMLNode& other)
 	 :	_attributes(other._attributes),
+		_leading(other._leading),
 		_content(other._content),
+		_end_leading(other._end_leading),
 		_trailing(other._trailing)
 	{
 		for(Children::const_iterator it=other._children.begin(); it!=other._children.end(); ++it)
@@ -312,7 +384,9 @@
 
 		_attributes = other._attributes;
 
+		_leading = other._leading;
 		_content = other._content;
+		_end_leading = other._end_leading;
 		_trailing = other._trailing;
 
 		return *this;
@@ -401,10 +475,24 @@
 		return _children;
 	}
 
+	String get_content() const
+	{
+		String ret;
+
+		assign_utf8(ret, _content.c_str());
+
+		return DecodeXMLString(ret);
+	}
+
+	void set_content(const String& s)
+	{
+		_content.assign(EncodeXMLString(s));
+	}
+
 	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
+		FORMAT_PRETTY	= 2 	/// pretty print node to stream without preserving original white space
 	};
 
 	 /// write node with children tree to output stream
@@ -412,15 +500,15 @@
 	{
 		switch(mode) {
 		  case FORMAT_PRETTY:
-			pretty_write_worker(out, mode, indent);
+			pretty_write_worker(out, indent);
 			break;
 
 		  case FORMAT_ORIGINAL:
-			write_worker(out, mode, indent);
+			write_worker(out, indent);
 			break;
 
 		default:	 // FORMAT_SMART
-			smart_write_worker(out, indent, _content.empty() && _trailing.empty());
+			smart_write_worker(out, indent);
 		}
 
 		return out;
@@ -430,8 +518,10 @@
 	Children _children;
 	AttributeMap _attributes;
 
-	std::string	_content;
-	std::string	_trailing;
+	std::string _leading;
+	std::string _content;
+	std::string _end_leading;
+	std::string _trailing;
 
 	XMLNode* get_first_child() const
 	{
@@ -488,10 +578,10 @@
 
 	void append_content(const char* s, int l)
 	{
-		if (_children.empty())
+		//if (_children.empty())
 			_content.append(s, l);
-		else
-			_children.back()->_content.append(s, l);
+		//else
+		//	_children.back()->_content.append(s, l);
 	}
 
 	void append_trailing(const char* s, int l)
@@ -502,9 +592,9 @@
 			_children.back()->_trailing.append(s, l);
 	}
 
-	void write_worker(std::ostream& out, WRITE_MODE mode, int indent) const;
-	void pretty_write_worker(std::ostream& out, WRITE_MODE mode, int indent) const;
-	bool smart_write_worker(std::ostream& out, int indent, bool next_format) const;
+	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;
 };
 
 
@@ -606,6 +696,104 @@
 };
 
 
+ /// read only iterator access to children nodes with name filtering
+struct const_XMLChildrenFilter
+{
+	const_XMLChildrenFilter(const XMLNode::Children& children, const String& name)
+	 :	_begin(children.begin(), children.end(), name),
+		_end(children.end(), children.end(), name)
+	{
+	}
+
+	const_XMLChildrenFilter(const XMLNode* node, const String& name)
+	 :	_begin(node->get_children().begin(), node->get_children().end(), name),
+		_end(node->get_children().end(), node->get_children().end(), name)
+	{
+	}
+
+	struct const_iterator
+	{
+		typedef XMLNode::Children::const_iterator BaseIterator;
+
+		const_iterator(BaseIterator begin, BaseIterator end, const String& filter_name)
+		 :	_cur(begin),
+			_end(end),
+			_filter_name(filter_name)
+		{
+			search_next();
+		}
+
+		operator BaseIterator()
+		{
+			return _cur;
+		}
+
+		const XMLNode* operator*() const
+		{
+			return *_cur;
+		}
+
+		XMLNode* operator*()
+		{
+			return *_cur;
+		}
+
+		const_iterator& operator++()
+		{
+			++_cur;
+			search_next();
+
+			return *this;
+		}
+
+		const_iterator operator++(int)
+		{
+			const_iterator ret = *this;
+
+			++_cur;
+			search_next();
+
+			return ret;
+		}
+
+		bool operator==(const BaseIterator& other) const
+		{
+			return _cur == other;
+		}
+
+		bool operator!=(const BaseIterator& other) const
+		{
+			return _cur != other;
+		}
+
+	protected:
+		BaseIterator	_cur;
+		BaseIterator	_end;
+		String	_filter_name;
+
+		void search_next()
+		{
+			while(_cur!=_end && **_cur!=_filter_name)
+				++_cur;
+		}
+	};
+
+	const_iterator begin()
+	{
+		return _begin;
+	}
+
+	const_iterator end()
+	{
+		return _end;
+	}
+
+protected:
+	const_iterator	_begin;
+	const_iterator	_end;
+};
+
+
  /// iterator for XML trees
 struct XMLPos
 {
@@ -622,8 +810,8 @@
 	}
 
 	 /// access to current node
-	operator XMLNode*() {return _cur;}
 	operator const XMLNode*() const {return _cur;}
+	operator XMLNode*() {return _cur;}
 
 	const XMLNode* operator->() const {return _cur;}
 	XMLNode* operator->() {return _cur;}
@@ -632,8 +820,8 @@
 	XMLNode& operator*() {return *_cur;}
 
 	 /// attribute access
-	String& operator[](const String& attr_name) {return (*_cur)[attr_name];}
 	template<typename T> String get(const T& attr_name) const {return (*_cur)[attr_name];}
+	String& operator[](const String& attr_name) {return (*_cur)[attr_name];}
 
 	 /// insert children when building tree
 	void add_down(XMLNode* child)
@@ -680,9 +868,15 @@
 	 /// move X-Path like to position in XML tree
 	bool go(const char* path);
 
-	 /// create node if not already existing and move to it
+	 /// create node and move to it
 	void create(const String& name)
 	{
+		add_down(new XMLNode(name));
+	}
+
+	 /// create node if not already existing and move to it
+	void smart_create(const String& name)
+	{
 		XMLNode* node = _cur->find_first(name);
 
 		if (node)
@@ -692,7 +886,7 @@
 	}
 
 	 /// search matching child node identified by key name and an attribute value
-	void create(const String& name, const String& attr_name, const String& attr_value)
+	void smart_create(const String& name, const String& attr_name, const String& attr_value)
 	{
 		XMLNode* node = _cur->find_first(name, attr_name, attr_value);
 
@@ -718,9 +912,15 @@
 			return false;
 	}
 
-	 /// create node if not already existing and move to it
+	 /// create node and move to it
 	void create(const char* name)
 	{
+		add_down(new XMLNode(name));
+	}
+
+	 /// create node if not already existing and move to it
+	void smart_create(const char* name)
+	{
 		XMLNode* node = _cur->find_first(name);
 
 		if (node)
@@ -731,7 +931,7 @@
 
 	 /// search matching child node identified by key name and an attribute value
 	template<typename T, typename U>
-	void create(const char* name, const T& attr_name, const U& attr_value)
+	void smart_create(const char* name, const T& attr_name, const U& attr_value)
 	{
 		XMLNode* node = _cur->find_first(name, attr_name, attr_value);
 
@@ -759,6 +959,97 @@
 };
 
 
+ /// iterator for XML trees
+struct const_XMLPos
+{
+	const_XMLPos(const XMLNode* root)
+	 :	_root(root),
+		_cur(root)
+	{
+	}
+
+	const_XMLPos(const const_XMLPos& other)
+	 :	_root(other._root),
+		_cur(other._cur)
+	{	// don't copy _stack
+	}
+
+	 /// access to current node
+	operator const XMLNode*() const {return _cur;}
+
+	const XMLNode* operator->() const {return _cur;}
+
+	const XMLNode& operator*() const {return *_cur;}
+
+	 /// attribute access
+	template<typename T> String get(const T& attr_name) const {return _cur->get(attr_name);}
+
+	 /// go back to previous position
+	bool back()
+	{
+		if (!_stack.empty()) {
+			_cur = _stack.top();
+			_stack.pop();
+			return true;
+		} else
+			return false;
+	}
+
+	 /// go down to first child
+	bool go_down()
+	{
+		const XMLNode* node = _cur->get_first_child();
+
+		if (node) {
+			go_to(node);
+			return true;
+		} else
+			return false;
+	}
+
+	 /// search for child and go down
+	bool go_down(const String& name)
+	{
+		XMLNode* node = _cur->find_first(name);
+
+		if (node) {
+			go_to(node);
+			return true;
+		} else
+			return false;
+	}
+
+	 /// move X-Path like to position in XML tree
+	bool go(const char* path);
+
+#ifdef UNICODE
+	 /// search for child and go down
+	bool go_down(const char* name)
+	{
+		XMLNode* node = _cur->find_first(name);
+
+		if (node) {
+			go_to(node);
+			return true;
+		} else
+			return false;
+	}
+#endif
+
+protected:
+	const XMLNode* _root;
+	const XMLNode* _cur;
+	std::stack<const XMLNode*> _stack;
+
+	 /// go to specified node
+	void go_to(const XMLNode* child)
+	{
+		_stack.push(_cur);
+		_cur = child;
+	}
+};
+
+
 struct XMLBool
 {
 	XMLBool(bool value)
@@ -789,6 +1080,11 @@
 		return _value;
 	}
 
+	bool operator!() const
+	{
+		return !_value;
+	}
+
 	operator LPCTSTR() const
 	{
 		return _value? TEXT("TRUE"): TEXT("FALSE");
@@ -798,7 +1094,7 @@
 	bool	_value;
 
 private:
-	void operator=(const XMLBool&);	// disallow assignment operations
+	void operator=(const XMLBool&); // disallow assignment operations
 };
 
 struct XMLBoolRef
@@ -815,6 +1111,11 @@
 		return !_tcsicmp(_ref, TEXT("TRUE"));
 	}
 
+	bool operator!() const
+	{
+		return _tcsicmp(_ref, TEXT("TRUE"))? true: false;
+	}
+
 	XMLBoolRef& operator=(bool value)
 	{
 		assign(value);
@@ -833,7 +1134,7 @@
 	}
 
 protected:
-	String&	_ref;
+	String& _ref;
 };
 
 
@@ -875,10 +1176,10 @@
 	}
 
 protected:
-	int	_value;
+	int _value;
 
 private:
-	void operator=(const XMLBool&);	// disallow assignment operations
+	void operator=(const XMLBool&); // disallow assignment operations
 };
 
 struct XMLNumberRef
@@ -911,7 +1212,7 @@
 	}
 
 protected:
-	String&	_ref;
+	String& _ref;
 };
 
 
@@ -931,7 +1232,7 @@
 		XML_SetElementHandler(_parser, XML_StartElementHandler, XML_EndElementHandler);
 		XML_SetDefaultHandler(_parser, XML_DefaultHandler);
 
-		_in_tag = false;
+		_in_node = false;
 	}
 
 	~XMLReader()
@@ -939,28 +1240,7 @@
 		XML_ParserFree(_parser);
 	}
 
-	XML_Status read(std::istream& in)
-	{
-		XML_Status status = XML_STATUS_OK;
-
-		while(in.good() && status==XML_STATUS_OK) {
-			char* buffer = (char*) XML_GetBuffer(_parser, BUFFER_LEN);
-
-			in.read(buffer, BUFFER_LEN);
-
-			status = XML_ParseBuffer(_parser, in.gcount(), false);
-		}
-
-		if (status != XML_STATUS_ERROR)
-			status = XML_ParseBuffer(_parser, 0, true);
-
-	/*
-		if (status == XML_STATUS_ERROR)
-			cerr << path << get_error_string();
-	*/
-
-		return status;
-	}
+	XML_Status read(std::istream& in);
 
 	std::string get_position() const
 	{
@@ -986,9 +1266,11 @@
 protected:
 	XMLPos		_pos;
 	XML_Parser	_parser;
-	std::string	_xml_version;
-	std::string	_encoding;
-	bool		_in_tag;
+	std::string _xml_version;
+	std::string _encoding;
+
+	std::string _content;
+	bool		_in_node;
 
 	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);
@@ -997,6 +1279,29 @@
 };
 
 
+struct XMLHeader : public std::string
+{
+	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)
+	{
+	}
+
+	void print(std::ostream& out) const
+	{
+		out << "<?xml version=\"" << _version << "\" encoding=\"" << _encoding << "\"?>\n";
+
+		if (!_doctype.empty())
+			out << _doctype << '\n';
+	}
+
+	std::string	_version;
+	std::string	_encoding;
+	std::string	_doctype;
+};
+
+
 struct XMLDoc : public XMLNode
 {
 	XMLDoc()
@@ -1004,7 +1309,7 @@
 	{
 	}
 
-	XMLDoc(const std::string& path)
+	XMLDoc(LPCTSTR path)
 	 :	XMLNode("")
 	{
 		read(path);
@@ -1012,23 +1317,33 @@
 
 	std::istream& read(std::istream& in)
 	{
-		XMLReader(this).read(in);
+		XMLReader reader(this);
 
+		/*XML_Status status = */reader.read(in);
+/*
+		if (status == XML_STATUS_ERROR)
+			cerr << reader.get_error_string();
+*/
 		return in;
 	}
 
-	bool read(const std::string& path)
+	bool read(LPCTSTR path)
 	{
-		std::ifstream in(path.c_str());
+		tifstream in(path);
+		XMLReader reader(this);
 
-		return XMLReader(this).read(in) != XML_STATUS_ERROR;
+		XML_Status status = reader.read(in);
+/*
+		if (status == XML_STATUS_ERROR)
+			cerr << path << reader.get_error_string();
+*/
+		return status != XML_STATUS_ERROR;
 	}
 
 	 /// write XML stream preserving previous white space and comments
-	std::ostream& write(std::ostream& out, WRITE_MODE mode=FORMAT_SMART,
-						const std::string& xml_version="1.0", const std::string& encoding="UTF-8") const
+	std::ostream& write(std::ostream& out, WRITE_MODE mode=FORMAT_SMART, const XMLHeader& header=XMLHeader()) const
 	{
-		out << "<?xml version=\"" << xml_version << "\" encoding=\"" << encoding << "\"?>\n";
+		header.print(out);
 
 		if (!_children.empty())
 			_children.front()->write(out);
@@ -1042,17 +1357,16 @@
 		return write(out, FORMAT_PRETTY);
 	}
 
-	void write(const std::string& path, WRITE_MODE mode=FORMAT_SMART,
-				const std::string& xml_version="1.0", const std::string& encoding="UTF-8") const
+	void write(LPCTSTR path, WRITE_MODE mode=FORMAT_SMART, const XMLHeader& header=XMLHeader()) const
 	{
-		std::ofstream out(path.c_str());
+		tofstream out(path);
 
-		write(out, mode, xml_version, encoding);
+		write(out, mode, header);
 	}
 
-	void write_formating(const std::string& path) const
+	void write_formating(LPCTSTR path) const
 	{
-		std::ofstream out(path.c_str());
+		tofstream out(path);
 
 		write_formating(out);
 	}
CVSspam 0.2.8