[ros-diffs] [martinf] 33226: update to XMLStorage version 1.3

martinf at svn.reactos.org martinf at svn.reactos.org
Thu May 1 23:17:36 CEST 2008


Author: martinf
Date: Thu May  1 16:17:35 2008
New Revision: 33226

URL: http://svn.reactos.org/svn/reactos?rev=33226&view=rev
Log:
update to XMLStorage version 1.3

Modified:
    trunk/reactos/base/shell/explorer/utility/xmlstorage.cpp
    trunk/reactos/base/shell/explorer/utility/xmlstorage.h
    trunk/reactos/base/shell/explorer/utility/xs-native.cpp

Modified: trunk/reactos/base/shell/explorer/utility/xmlstorage.cpp
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/explorer/utility/xmlstorage.cpp?rev=33226&r1=33225&r2=33226&view=diff
==============================================================================
--- trunk/reactos/base/shell/explorer/utility/xmlstorage.cpp [iso-8859-1] (original)
+++ trunk/reactos/base/shell/explorer/utility/xmlstorage.cpp [iso-8859-1] Thu May  1 16:17:35 2008
@@ -1,8 +1,8 @@
 
  //
- // XML storage C++ classes version 1.2
+ // XML storage C++ classes version 1.3
  //
- // Copyright (c) 2004, 2005, 2006, 2007 Martin Fuchs <martin-fuchs at gmx.net>
+ // Copyright (c) 2004, 2005, 2006, 2007, 2008 Martin Fuchs <martin-fuchs at gmx.net>
  //
 
  /// \file xmlstorage.cpp
@@ -57,6 +57,10 @@
 const LPCXSSTR XS_FLOATFMT = XS_FLOATFMT_STR;
 #endif
 
+const XS_String XS_KEY = XS_KEY_STR;
+const XS_String XS_VALUE = XS_VALUE_STR;
+const XS_String XS_PROPERTY = XS_PROPERTY_STR;
+
 
  /// remove escape characters from zero terminated string
 static std::string unescape(const char* s, char b, char e)
@@ -105,18 +109,12 @@
 }
 
 
- /// move XPath like to position in XML tree
-bool XMLPos::go(const char* path)
-{
-	XMLNode* node = _cur;
-
-	 // Is this an absolute path?
-	if (*path == '/') {
-		node = _root;
-		++path;
-	}
-
-	node = node->find_relative(path);
+ /// move to the position defined by xpath in XML tree
+bool XMLPos::go(const XPath& xpath)
+{
+	XMLNode* node = xpath._absolute? _root: _cur;
+
+	node = node->find_relative(xpath);
 
 	if (node) {
 		go_to(node);
@@ -125,18 +123,12 @@
 		return false;
 }
 
- /// move XPath like to position in XML tree
-bool const_XMLPos::go(const char* path)
-{
-	const XMLNode* node = _cur;
-
-	 // Is this an absolute path?
-	if (*path == '/') {
-		node = _root;
-		++path;
-	}
-
-	node = node->find_relative(path);
+ /// move to the position defined by xpath in XML tree
+bool const_XMLPos::go(const XPath& xpath)
+{
+	const XMLNode* node = xpath._absolute? _root: _cur;
+
+	node = node->find_relative(xpath);
 
 	if (node) {
 		go_to(node);
@@ -146,40 +138,7 @@
 }
 
 
-const XMLNode* XMLNode::find_relative(const char* path) const
-{
-	const XMLNode* node = this;
-
-	 // parse relative path
-	while(*path) {
-		node = const_cast<XMLNode*>(node)->get_child_relative(path, false);	// get_child_relative() ist const for create==false
-
-		if (!node)
-			return NULL;
-
-		if (*path == '/')
-			++path;
-	}
-
-	return node;
-}
-
-XMLNode* XMLNode::create_relative(const char* path)
-{
-	XMLNode* node = this;
-
-	 // parse relative path
-	while(*path) {
-		node = node->get_child_relative(path, true);
-
-		if (*path == '/')
-			++path;
-	}
-
-	return node;
-}
-
-XMLNode* XMLNode::get_child_relative(const char*& path, bool create)
+const char* XPathElement::parse(const char* path)
 {
 	const char* slash = strchr(path, '/');
 	if (slash == path)
@@ -192,8 +151,7 @@
 	 // look for [n] and [@attr_name="attr_value"] expressions in path components
 	const char* bracket = strchr(comp.c_str(), '[');
 	l = bracket? bracket-comp.c_str(): comp.length();
-	std::string child_name(comp.c_str(), l);
-	std::string attr_name, attr_value;
+	_child_name.assign(comp.c_str(), l);
 
 	int n = 0;
 	if (bracket) {
@@ -203,7 +161,7 @@
 		n = atoi(p);	// read index number
 
 		if (n)
-			n = n - 1;	// convert into zero based index
+			_child_idx = n - 1;	// convert into zero based index
 
 		const char* at = strchr(p, '@');
 
@@ -213,30 +171,198 @@
 
 			 // read attribute name and value
 			if (equal) {
-				attr_name = unescape(p, equal-p);
-				attr_value = unescape(equal+1);
+				_attr_name = unescape(p, equal-p);
+				_attr_value = unescape(equal+1);
 			}
 		}
 	}
 
-	XMLNode* child;
-
-	if (attr_name.empty())
-		 // search n.th child node with specified name
-		child = find(child_name, n);
+	return path;
+}
+
+XMLNode* XPathElement::find(XMLNode* node) const
+{
+	int n = 0;
+
+	for(XMLNode::Children::const_iterator it=node->_children.begin(); it!=node->_children.end(); ++it)
+		if (matches(**it, n))
+			return *it;
+
+	return NULL;
+}
+
+const XMLNode* XPathElement::const_find(const XMLNode* node) const
+{
+	int n = 0;
+
+	for(XMLNode::Children::const_iterator it=node->_children.begin(); it!=node->_children.end(); ++it)
+		if (matches(**it, n))
+			return *it;
+
+	return NULL;
+}
+
+bool XPathElement::matches(const XMLNode& node, int& n) const
+{
+	if (node != _child_name)
+		if (_child_name != XS_TEXT("*"))	// use asterisk as wildcard
+			return false;
+
+	if (!_attr_name.empty())
+		if (node.get(_attr_name) != _attr_value)
+			return false;
+
+	if (_child_idx == -1)
+		return true;
+	else if (n++ == _child_idx)
+		return true;
 	else
-		 // search n.th child node with specified name and matching attribute value
-		child = find(child_name, attr_name, attr_value, n);
-
-	if (!child && create) {
-		child = new XMLNode(child_name);
-		add_child(child);
-
-		if (!attr_name.empty())
-			(*this)[attr_name] = attr_value;
-	}
-
-	return child;
+		return false;
+}
+
+
+void XPath::init(const char* path)
+{
+	 // Is this an absolute path?
+	if (*path == '/') {
+		_absolute = true;
+		++path;
+	} else
+		_absolute = false;
+
+	 // parse path
+	while(*path) {
+		XPathElement elem;
+
+		path = elem.parse(path);
+
+		if (!path)
+			break;
+
+		if (*path == '/')
+			++path;
+
+		push_back(elem);
+	}
+}
+
+
+const XMLNode* XMLNode::find_relative(const XPath& xpath) const
+{
+	const XMLNode* node = this;
+
+	for(XPath::const_iterator it=xpath.begin(); it!=xpath.end(); ++it) {
+		node = it->const_find(node);
+
+		if (!node)
+			return NULL;
+	}
+
+	return node;
+}
+
+XMLNode* XMLNode::find_relative(const XPath& xpath)
+{
+	XMLNode* node = this;
+
+	for(XPath::const_iterator it=xpath.begin(); it!=xpath.end(); ++it) {
+		node = it->find(node);
+
+		if (!node)
+			return NULL;
+	}
+
+	return node;
+}
+
+XMLNode* XMLNode::create_relative(const XPath& xpath)
+{
+	XMLNode* node = this;
+
+	for(XPath::const_iterator it=xpath.begin(); it!=xpath.end(); ++it) {
+		XMLNode* child = it->find(this);
+
+		if (!child) {
+			child = new XMLNode(it->_child_name);
+			add_child(child);
+
+			if (!it->_attr_name.empty())
+				(*this)[it->_attr_name] = it->_attr_value;
+		}
+	}
+
+	return node;
+}
+
+ /// count the nodes matching the given relative XPath expression
+int XMLNode::count(XPath::const_iterator from, const XPath::const_iterator& to) const
+{
+	const XPathElement& elem = *from++;
+	int cnt = 0;
+	int n = 0;
+
+	for(XMLNode::Children::const_iterator it=_children.begin(); it!=_children.end(); ++it)
+		if (elem.matches(**it, n))
+			if (from != to)
+				 // iterate deeper
+				cnt += (*it)->count(from, to);
+			else
+				 // increment match counter
+				++cnt;
+
+	return cnt;
+}
+
+ /// copy matching tree nodes using the given XPath filter expression
+bool XMLNode::filter(const XPath& xpath, XMLNode& target) const
+{
+	XMLNode* ret = filter(xpath.begin(), xpath.end());
+
+	if (ret) {
+		 // move returned nodes to target node
+		target._children.move(ret->_children);
+		target._attributes = ret->_attributes;
+
+		delete ret;
+
+		return true;
+	} else
+		return false;
+}
+
+ /// create a new node tree using the given XPath filter expression
+XMLNode* XMLNode::filter(XPath::const_iterator from, const XPath::const_iterator& to) const
+{
+	XMLNode* copy = NULL;
+
+	const XPathElement& elem = *from++;
+	int cnt = 0;
+	int n = 0;
+
+	for(XMLNode::Children::const_iterator it=_children.begin(); it!=_children.end(); ++it)
+		if (elem.matches(**it, n)) {
+			if (!copy)
+				copy = new XMLNode(*this, XMLNode::COPY_NOCHILDREN);
+
+			if (from != to) {
+				XMLNode* ret = (*it)->filter(from, to);
+
+				if (ret) {
+					copy->add_child(ret);
+					++cnt;
+				}
+			} else {
+				copy->add_child(new XMLNode(**it, XMLNode::COPY_NOCHILDREN));
+				++cnt;
+			}
+		}
+
+	if (cnt > 0) {
+		return copy;
+	} else {
+		delete copy;
+		return NULL;
+	}
 }
 
 
@@ -286,9 +412,9 @@
 				break;
 
 			  default:
-				if ((unsigned)*p<20 && *p!='\t' && *p!='\r' && *p!='\n') {
+				if ((unsigned)*p<0x20 && *p!='\t' && *p!='\r' && *p!='\n') {
 					char b[16];
-					sprintf(b, "&%d;", (unsigned)*p);
+					sprintf(b, "&#%d;", (unsigned)*p);
 					for(const char*q=b; *q; )
 						*o++ = *q++;
 				} else
@@ -330,8 +456,8 @@
 				break;
 
 			  default:
-				if ((unsigned)*p<20 && *p!='\t' && *p!='\r' && *p!='\n')
-					out << "&" << (unsigned)*p << ";";
+				if ((unsigned)*p<0x20 && *p!='\t' && *p!='\r' && *p!='\n')
+					out << "&#" << (unsigned)*p << ";";
 				else
 					out << *p;
 			}
@@ -368,7 +494,7 @@
 			} else if (!XS_nicmp(p+1, XS_TEXT("apos;"), 5)) {
 				*o++ = '\'';
 				p += 5;
-			} else
+			} else	//@@ maybe decode "&#xx;" special characters
 				*o++ = *p;
 		} else if (*p=='<' && !XS_nicmp(p+1,XS_TEXT("![CDATA["),8)) {
 			LPCXSSTR e = XS_strstr(p+9, XS_TEXT("]]>"));
@@ -535,18 +661,33 @@
 }
 
 
+const char* get_xmlsym_end_utf8(const char* p)
+{
+	for(; *p; ++p) {
+		char c = *p;
+
+		if (c == '\xC3')	// UTF-8 escape character
+			++p;	//TODO only continue on umlaut characters
+		else if (!isalnum(c) && c!='_' && c!='-')
+			break;
+	}
+
+	return p;
+}
+
+
 void DocType::parse(const char* p)
 {
 	while(isspace((unsigned char)*p)) ++p;
 
 	const char* start = p;
-	while(isxmlsym(*p)) ++p;
+	p = get_xmlsym_end_utf8(p);
 	_name.assign(start, p-start);
 
 	while(isspace((unsigned char)*p)) ++p;
 
 	start = p;
-	while(isxmlsym(*p)) ++p;
+	p = get_xmlsym_end_utf8(p);
 	std::string keyword(p, p-start);	// "PUBLIC" or "SYSTEM"
 
 	while(isspace((unsigned char)*p)) ++p;
@@ -705,7 +846,6 @@
 			break;
 
 	if (p != s)
-	{
 		if (_pos->_children.empty()) {	// no children in last node?
 			if (_last_tag == TAG_START)
 				_pos->_content.append(s, p-s);
@@ -715,7 +855,7 @@
 				p = s;
 		} else
 			_pos->_children.back()->_trailing.append(s, p-s);
-	}
+
 	std::string leading;
 
 	if (p != e)
@@ -753,14 +893,12 @@
 	}
 
 	if (p != s)
-	{
 		if (_pos->_children.empty())	// no children in current node?
 			_pos->_content.append(s, p-s);
 		else if (_last_tag == TAG_START)
 			_pos->_content.append(s, p-s);
 		else
 			_pos->_children.back()->_trailing.append(s, p-s);
-	}
 
 	if (p != e)
 		_pos->_end_leading.assign(p, e-p);
@@ -786,5 +924,91 @@
 
 XS_String XMLWriter::s_empty_attr;
 
+void XMLWriter::create(const XS_String& name)
+{
+	if (!_stack.empty()) {
+		StackEntry& last = _stack.top();
+
+		if (last._state < PRE_CLOSED) {
+			write_attributes(last);
+			close_pre(last);
+		}
+
+		++last._children;
+	}
+
+	StackEntry entry;
+	entry._node_name = name;
+	_stack.push(entry);
+
+	write_pre(entry);
+}
+
+bool XMLWriter::back()
+{
+	if (!_stack.empty()) {
+		write_post(_stack.top());
+
+		_stack.pop();
+		return true;
+	} else
+		return false;
+}
+
+void XMLWriter::close_pre(StackEntry& entry)
+{
+	_out << '>';
+
+	entry._state = PRE_CLOSED;
+}
+
+void XMLWriter::write_pre(StackEntry& entry)
+{
+	if (_format._pretty >= PRETTY_LINEFEED)
+		_out << _format._endl;
+
+	if (_format._pretty == PRETTY_INDENT)
+		for(size_t i=_stack.size(); --i>0; )
+			_out << XML_INDENT_SPACE;
+
+	_out << '<' << EncodeXMLString(entry._node_name);
+	//entry._state = PRE;
+}
+
+void XMLWriter::write_attributes(StackEntry& entry)
+{
+	for(AttrMap::const_iterator it=entry._attributes.begin(); it!=entry._attributes.end(); ++it)
+		_out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\"";
+
+	entry._state = ATTRIBUTES;
+}
+
+void XMLWriter::write_post(StackEntry& entry)
+{
+	if (entry._state < ATTRIBUTES)
+		write_attributes(entry);
+
+	if (entry._children || !entry._content.empty()) {
+		if (entry._state < PRE_CLOSED)
+			close_pre(entry);
+
+		_out << entry._content;
+		//entry._state = CONTENT;
+
+		if (_format._pretty>=PRETTY_LINEFEED && entry._content.empty())
+			_out << _format._endl;
+
+		if (_format._pretty==PRETTY_INDENT && entry._content.empty())
+			for(size_t i=_stack.size(); --i>0; )
+				_out << XML_INDENT_SPACE;
+
+		_out << "</" << EncodeXMLString(entry._node_name) << ">";
+	} else {
+		_out << "/>";
+	}
+
+	entry._state = POST;
+}
+
 
 }	// namespace XMLStorage

Modified: trunk/reactos/base/shell/explorer/utility/xmlstorage.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/explorer/utility/xmlstorage.h?rev=33226&r1=33225&r2=33226&view=diff
==============================================================================
--- trunk/reactos/base/shell/explorer/utility/xmlstorage.h [iso-8859-1] (original)
+++ trunk/reactos/base/shell/explorer/utility/xmlstorage.h [iso-8859-1] Thu May  1 16:17:35 2008
@@ -1,8 +1,8 @@
 
  //
- // XML storage C++ classes version 1.2
+ // XML storage C++ classes version 1.3
  //
- // Copyright (c) 2004, 2005, 2006, 2007 Martin Fuchs <martin-fuchs at gmx.net>
+ // Copyright (c) 2004, 2005, 2006, 2007, 2008 Martin Fuchs <martin-fuchs at gmx.net>
  //
 
  /// \file xmlstorage.h
@@ -39,9 +39,6 @@
 
 #ifndef _XMLSTORAGE_H
 
-#ifndef __REACTOS__
-#include <strstream>
-#endif
 
 #ifdef UNICODE
 #ifndef _UNICODE
@@ -202,6 +199,10 @@
 #define _tcsnicmp strncasecmp
 #endif
 
+#endif
+
+#ifdef __BORLANDC__
+#define _stricmp stricmp
 #endif
 
 
@@ -264,10 +265,7 @@
 #endif
 
 
-int inline isxmlsym(unsigned char c)
-{
-	return isalnum(c) || c=='_' || c=='-';
-}
+extern const char* get_xmlsym_end_utf8(const char* p);
 
 
 #if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8)
@@ -397,6 +395,10 @@
 #define	XS_INTFMT_STR XS_TEXT("%d")
 #define	XS_FLOATFMT_STR XS_TEXT("%f")
 
+#define	XS_KEY_STR XS_TEXT("key")
+#define	XS_VALUE_STR XS_TEXT("value")
+#define	XS_PROPERTY_STR XS_TEXT("property")
+
  // work around GCC's wide string constant bug
 #ifdef __GNUC__
 extern const LPCXSSTR XS_EMPTY;
@@ -412,6 +414,10 @@
 #define	XS_FLOATFMT XS_FLOATFMT_STR
 #endif
 
+extern const XS_String XS_KEY;
+extern const XS_String XS_VALUE;
+extern const XS_String XS_PROPERTY;
+
 
 #ifndef XS_STRING_UTF8
 
@@ -783,6 +789,46 @@
 };
 
 
+struct XMLNode;
+
+struct XPathElement
+{
+	XPathElement() : _child_idx(-1) {}
+
+	XPathElement(const XS_String& child_name, int child_idx=-1)
+	 :	_child_name(child_name), _child_idx(child_idx) {}
+
+	XPathElement(const XS_String& child_name, int child_idx, const XS_String& attr_name, const XS_String& attr_value)
+	 :	_child_name(child_name), _child_idx(child_idx),
+		_attr_name(attr_name), _attr_value(attr_value)
+	{
+	}
+
+	XS_String	_child_name;
+	int			_child_idx;
+
+	XS_String	_attr_name;
+	XS_String	_attr_value;
+
+	const char* parse(const char* path);
+
+	XMLNode* find(XMLNode* node) const;
+	const XMLNode* const_find(const XMLNode* node) const;
+
+	bool	matches(const XMLNode& node, int& n) const;
+};
+
+struct XPath : std::list<XPathElement>
+{
+	XPath(const char* path) {init(path);}
+	XPath(const std::string path) {init(path.c_str());}
+
+	void	init(const char* path);
+
+	bool	_absolute;
+};
+
+
  /// in memory representation of an XML node
 struct XMLNode : public XS_String
 {
@@ -841,10 +887,40 @@
 	 /// internal children node list
 	struct Children : public std::list<XMLNode*>
 	{
-		void assign(const Children& other)
+		typedef std::list<XMLNode*> super;
+
+		Children()
+		{
+		}
+
+		Children(Children& other)
+		{
+			for(Children::const_iterator it=other.begin(); it!=other.end(); ++it)
+				push_back(*it);
+		}
+
+		void assign(Children& other)
 		{
 			clear();
-
+			move(other);
+		}
+
+		void move(Children& other)
+		{
+			for(Children::const_iterator it=other.begin(); it!=other.end(); ++it)
+				push_back(*it);
+
+			other.reset();
+		}
+
+		Children& operator=(Children& other)
+		{
+			assign(other);
+			return *this;
+		}
+
+		void copy(const Children& other)
+		{
 			for(Children::const_iterator it=other.begin(); it!=other.end(); ++it)
 				push_back(new XMLNode(**it));
 		}
@@ -858,6 +934,23 @@
 				node->clear();
 				delete node;
 			}
+		}
+
+		bool remove(XMLNode* node)
+		{
+			for(iterator it=begin(); it!=end(); ++it)
+				if (*it == node) {
+					erase(it);
+					return true;
+				}
+
+			return false;
+		}
+
+	private:
+		void reset()
+		{
+			super::clear();
 		}
 	};
 
@@ -865,6 +958,7 @@
 	friend struct XMLPos;
 	friend struct const_XMLPos;
 	friend struct XMLReaderBase;
+	friend struct XPathElement;
 
 	XMLNode(const XS_String& name)
 	 :	XS_String(name)
@@ -892,6 +986,22 @@
 			_children.push_back(new XMLNode(**it));
 	}
 
+	enum COPY_FLAGS {COPY_NOCHILDREN};
+
+	XMLNode(const XMLNode& other, COPY_FLAGS copy_no_children)
+	 :	XS_String(other),
+		_attributes(other._attributes),
+		_leading(other._leading),
+		_content(other._content),
+		_end_leading(other._end_leading),
+		_trailing(other._trailing)
+#ifdef XMLNODE_LOCATION
+		, _location(other._location)
+#endif
+	{
+//		assert(copy_no_children==COPY_NOCHILDREN);
+	}
+
 	virtual ~XMLNode()
 	{
 		while(!_children.empty()) {
@@ -915,7 +1025,8 @@
 
 	XMLNode& operator=(const XMLNode& other)
 	{
-		_children.assign(other._children);
+		_children.clear();
+		_children.copy(other._children);
 
 		_attributes = other._attributes;
 
@@ -933,6 +1044,16 @@
 		_children.push_back(child);
 	}
 
+	 /// remove all children named 'name'
+	void remove_children(const XS_String& name)
+	{
+		Children::iterator it, next=_children.begin();
+
+		while((it=next++)!=_children.end())
+			if (**it == name)
+				_children.erase(it);
+	}
+
 	 /// write access to an attribute
 	void put(const XS_String& attr_name, const XS_String& value)
 	{
@@ -956,10 +1077,16 @@
 			return def;
 	}
 
+	 /// remove the attribute 'attr_name'
+	void erase(const XS_String& attr_name)
+	{
+		_attributes.erase(attr_name);
+	}
+
 	 /// convenient value access in children node
-	XS_String subvalue(const XS_String& name, const XS_String& attr_name, int n=0) const
-	{
-		const XMLNode* node = find(name, n);
+	XS_String subvalue(const XS_String& child_name, const XS_String& attr_name, int n=0) const
+	{
+		const XMLNode* node = XPathElement(child_name, n).const_find(this);
 
 		if (node)
 			return node->get(attr_name);
@@ -968,12 +1095,12 @@
 	}
 
 	 /// convenient storage of distinct values in children node
-	XS_String& subvalue(const XS_String& name, const XS_String& attr_name, int n=0)
-	{
-		XMLNode* node = find(name, n);
+	XS_String& subvalue(const XS_String& child_name, const XS_String& attr_name, int n=0)
+	{
+		XMLNode* node = XPathElement(child_name, n).find(this);
 
 		if (!node) {
-			node = new XMLNode(name);
+			node = new XMLNode(child_name);
 			add_child(node);
 		}
 
@@ -982,9 +1109,9 @@
 
 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
 	 /// convenient value access in children node
-	XS_String subvalue(const char* name, const char* attr_name, int n=0) const
-	{
-		const XMLNode* node = find(name, n);
+	XS_String subvalue(const char* child_name, const char* attr_name, int n=0) const
+	{
+		const XMLNode* node = XPathElement(child_name, n).const_find(this);
 
 		if (node)
 			return node->get(attr_name);
@@ -993,12 +1120,12 @@
 	}
 
 	 /// convenient storage of distinct values in children node
-	XS_String& subvalue(const char* name, const XS_String& attr_name, int n=0)
-	{
-		XMLNode* node = find(name, n);
+	XS_String& subvalue(const char* child_name, const XS_String& attr_name, int n=0)
+	{
+		XMLNode* node = XPathElement(child_name, n).find(this);
 
 		if (!node) {
-			node = new XMLNode(name);
+			node = new XMLNode(child_name);
 			add_child(node);
 		}
 
@@ -1070,6 +1197,18 @@
 		return out.good();
 	}
 
+	 /// count the nodes matching the given relative XPath expression
+	int count(const XPath& xpath) const
+	{
+		return count(xpath.begin(), xpath.end());
+	}
+
+	 /// count the nodes matching the given relative XPath expression
+	int count(XPath::const_iterator from, const XPath::const_iterator& to) const;
+
+	 /// copy matching tree nodes using the given XPath filter expression
+	bool filter(const XPath& xpath, XMLNode& target) const;
+
 protected:
 	Children _children;
 	AttributeMap _attributes;
@@ -1091,72 +1230,22 @@
 			return NULL;
 	}
 
-	XMLNode* find(const XS_String& name, int n=0) const
-	{
-		for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it)
-			if (**it == name)
-				if (!n--)
-					return *it;
-
-		return NULL;
-	}
-
-	XMLNode* find(const XS_String& name, const XS_String& attr_name, const XS_String& attr_value, int n=0) const
-	{
-		for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it) {
-			const XMLNode& node = **it;
-
-			if (node==name && node.get(attr_name)==attr_value)
-				if (!n--)
-					return *it;
-		}
-
-		return NULL;
-	}
-
-#if defined(UNICODE) && !defined(XS_STRING_UTF8)
-	XMLNode* find(const char* name, int n=0) const
-	{
-		for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it)
-			if (**it == name)
-				if (!n--)
-					return *it;
-
-		return NULL;
-	}
-
-	template<typename T, typename U>
-	XMLNode* find(const char* name, const T& attr_name, const U& attr_value, int n=0) const
-	{
-		for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it) {
-			const XMLNode& node = **it;
-
-			if (node==name && node.get(attr_name)==attr_value)
-				if (!n--)
-					return *it;
-		}
-
-		return NULL;
-	}
-#endif
-
 	 /// XPath find function (const)
-	const XMLNode* find_relative(const char* path) const;
+	const XMLNode* find_relative(const XPath& xpath) const;
 
 	 /// XPath find function
-	XMLNode* find_relative(const char* path)
-		{return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->find_relative(path));}
+	XMLNode* find_relative(const XPath& xpath);
 
 	 /// relative XPath create function
-	XMLNode* create_relative(const char* path);
+	XMLNode* create_relative(const XPath& xpath);
+
+	 /// create a new node tree using the given XPath filter expression
+	XMLNode* filter(XPath::const_iterator from, const XPath::const_iterator& to) const;
 
 	void	write_worker(std::ostream& out) 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;
-
-protected:
-	XMLNode* get_child_relative(const char*& path, bool create); // mutable for create==true
 };
 
 
@@ -1179,6 +1268,7 @@
 	struct iterator
 	{
 		typedef XMLNode::Children::iterator BaseIterator;
+		typedef iterator myType;
 
 		iterator(BaseIterator begin, BaseIterator end, const XS_String& filter_name)
 		 :	_cur(begin),
@@ -1203,7 +1293,7 @@
 			return *_cur;
 		}
 
-		iterator& operator++()
+		myType& operator++()
 		{
 			++_cur;
 			search_next();
@@ -1211,9 +1301,9 @@
 			return *this;
 		}
 
-		iterator operator++(int)
-		{
-			iterator ret = *this;
+		myType operator++(int)
+		{
+			myType ret = *this;
 
 			++_cur;
 			search_next();
@@ -1221,14 +1311,14 @@
 			return ret;
 		}
 
-		bool operator==(const BaseIterator& other) const
-		{
-			return _cur == other;
-		}
-
-		bool operator!=(const BaseIterator& other) const
-		{
-			return _cur != other;
+		bool operator==(const myType& other) const
+		{
+			return _cur == other._cur;
+		}
+
+		bool operator!=(const myType& other) const
+		{
+			return _cur != other._cur;
 		}
 
 	protected:
@@ -1278,6 +1368,7 @@
 	struct const_iterator
 	{
 		typedef XMLNode::Children::const_iterator BaseIterator;
+		typedef const_iterator myType;
 
 		const_iterator(BaseIterator begin, BaseIterator end, const XS_String& filter_name)
 		 :	_cur(begin),
@@ -1297,7 +1388,7 @@
 			return *_cur;
 		}
 
-		const_iterator& operator++()
+		myType& operator++()
 		{
 			++_cur;
 			search_next();
@@ -1305,9 +1396,9 @@
 			return *this;
 		}
 
-		const_iterator operator++(int)
-		{
-			const_iterator ret = *this;
+		myType operator++(int)
+		{
+			myType ret = *this;
 
 			++_cur;
 			search_next();
@@ -1315,14 +1406,14 @@
 			return ret;
 		}
 
-		bool operator==(const BaseIterator& other) const
-		{
-			return _cur == other;
-		}
-
-		bool operator!=(const BaseIterator& other) const
-		{
-			return _cur != other;
+		bool operator==(const myType& other) const
+		{
+			return _cur == other._cur;
+		}
+
+		bool operator!=(const myType& other) const
+		{
+			return _cur != other._cur;
 		}
 
 	protected:
@@ -1464,9 +1555,9 @@
 	}
 
 	 /// search for child and go down
-	bool go_down(const XS_String& name, int n=0)
-	{
-		XMLNode* node = _cur->find(name, n);
+	bool go_down(const XS_String& child_name, int n=0)
+	{
+		XMLNode* node = XPathElement(child_name, n).find(_cur);
 
 		if (node) {
 			go_to(node);
@@ -1475,13 +1566,13 @@
 			return false;
 	}
 
-	 /// move XPath like to position in XML tree
-	bool go(const char* path);
+	 /// move to the position defined by xpath in XML tree
+	bool go(const XPath& xpath);
 
 	 /// create child nodes using XPath notation and move to the deepest child
-	bool create_relative(const char* path)
-	{
-		XMLNode* node = _cur->create_relative(path);
+	bool create_relative(const XPath& xpath)
+	{
+		XMLNode* node = _cur->create_relative(xpath);
 		if (!node)
 			return false;	// invalid path specified
 
@@ -1496,35 +1587,47 @@
 	}
 
 	 /// create node if not already existing and move to it
-	void smart_create(const XS_String& name)
-	{
-		XMLNode* node = _cur->find(name);
+	void smart_create(const XS_String& child_name)
+	{
+		XMLNode* node = XPathElement(child_name).find(_cur);
 
 		if (node)
 			go_to(node);
 		else
-			add_down(new XMLNode(name));
+			add_down(new XMLNode(child_name));
 	}
 
 	 /// search matching child node identified by key name and an attribute value
-	void smart_create(const XS_String& name, const XS_String& attr_name, const XS_String& attr_value)
-	{
-		XMLNode* node = _cur->find(name, attr_name, attr_value);
+	void smart_create(const XS_String& child_name, const XS_String& attr_name, const XS_String& attr_value)
+	{
+		XMLNode* node = XPathElement(child_name, 0, attr_name, attr_value).find(_cur);
 
 		if (node)
 			go_to(node);
 		else {
-			node = new XMLNode(name);
+			node = new XMLNode(child_name);
 			add_down(node);
 			(*node)[attr_name] = attr_value;
 		}
 	}
 
+	 /// count the nodes matching the given relative XPath expression
+	int count(const XPath& xpath) const
+	{
+		return _cur->count(xpath);
+	}
+
+	 /// create a new node tree using the given XPath filter expression
+	int filter(const XPath& xpath, XMLNode& target) const
+	{
+		return _cur->filter(xpath, target);
+	}
+
 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
 	 /// search for child and go down
-	bool go_down(const char* name, int n=0)
-	{
-		XMLNode* node = _cur->find(name, n);
+	bool go_down(const char* child_name, int n=0)
+	{
+		XMLNode* node = XPathElement(child_name, n).find(_cur);
 
 		if (node) {
 			go_to(node);
@@ -1534,40 +1637,76 @@
 	}
 
 	 /// create node and move to it
-	void create(const char* name)
-	{
-		add_down(new XMLNode(name));
+	void create(const char* child_name)
+	{
+		add_down(new XMLNode(child_name));
 	}
 
 	 /// create node if not already existing and move to it
-	void smart_create(const char* name)
-	{
-		XMLNode* node = _cur->find(name);
+	void smart_create(const char* child_name)
+	{
+		XMLNode* node = XPathElement(child_name).find(_cur);
 
 		if (node)
 			go_to(node);
 		else
-			add_down(new XMLNode(name));
+			add_down(new XMLNode(child_name));
 	}
 
 	 /// search matching child node identified by key name and an attribute value
 	template<typename T, typename U>
-	void smart_create(const char* name, const T& attr_name, const U& attr_value)
-	{
-		XMLNode* node = _cur->find(name, attr_name, attr_value);
+	void smart_create(const char* child_name, const T& attr_name, const U& attr_value)
+	{
+		XMLNode* node = XPathElement(child_name, 0, attr_name, attr_value).find(_cur);
 
 		if (node)
 			go_to(node);
 		else {
-			XMLNode* node = new XMLNode(name);
+			node = new XMLNode(child_name);
 			add_down(node);
 			(*node)[attr_name] = attr_value;
 		}
 	}
 #endif
 
+	 /// delete current node and go back to previous position
+	bool delete_this()
+	{
+		if (!_stack.empty()) {
+			XMLNode* pLast = _stack.top();
+
+			if (pLast->_children.remove(_cur)) {
+				_cur = _stack.top();
+				return true;
+			}
+		}
+
+		return false;
+	}
+
+	 /// remove all children named 'name'
+	void remove_children(const XS_String& name)
+	{
+		_cur->remove_children(name);
+	}
+
+	 /// remove the attribute 'attr_name' from the current node
+	void erase(const XS_String& attr_name)
+	{
+		_cur->erase(attr_name);
+	}
+
 	XS_String& str() {return *_cur;}
 	const XS_String& str() const {return *_cur;}
+
+	 // property (key/value pair) setter functions
+	void set_property(const XS_String& key, int value, const XS_String& name=XS_PROPERTY);
+	void set_property(const XS_String& key, double value, const XS_String& name=XS_PROPERTY);
+	void set_property(const XS_String& key, const XS_String& value, const XS_String& name=XS_PROPERTY);
+	void set_property(const XS_String& key, const struct XMLBool& value, const XS_String& name=XS_PROPERTY);
+
+	void set_property(const XS_String& key, const char* value, const XS_String& name=XS_PROPERTY)
+		{set_property(key, XS_String(value), name);}
 
 protected:
 	XMLNode* _root;
@@ -1644,9 +1783,9 @@
 	}
 
 	 /// search for child and go down
-	bool go_down(const XS_String& name, int n=0)
-	{
-		XMLNode* node = _cur->find(name, n);
+	bool go_down(const XS_String& child_name, int n=0)
+	{
+		const XMLNode* node = XPathElement(child_name, n).const_find(_cur);
 
 		if (node) {
 			go_to(node);
@@ -1655,14 +1794,14 @@
 			return false;
 	}
 
-	 /// move XPath like to position in XML tree
-	bool go(const char* path);
+	 /// move to the position defined by xpath in XML tree
+	bool go(const XPath& xpath);
 
 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
 	 /// search for child and go down
-	bool go_down(const char* name, int n=0)
-	{
-		XMLNode* node = _cur->find(name, n);
+	bool go_down(const char* child_name, int n=0)
+	{
+		const XMLNode* node = XPathElement(child_name, n).const_find(_cur);
 
 		if (node) {
 			go_to(node);
@@ -1698,7 +1837,7 @@
 
 	XMLBool(LPCXSSTR value, bool def=false)
 	{
-		if (value && *value)
+		if (value && *value)//@@ also handle white space and return def instead of false
 			_value = !XS_icmp(value, XS_TRUE);
 		else
 			_value = def;
@@ -1788,7 +1927,7 @@
 
 	XMLInt(LPCXSSTR value, int def=0)
 	{
-		if (value && *value)
+		if (value && *value)//@@ also handle white space and return def instead of 0
 			_value = XS_toi(value);
 		else
 			_value = def;
@@ -1813,7 +1952,7 @@
 	{
 		XS_CHAR buffer[32];
 		XS_snprintf(buffer, COUNTOF(buffer), XS_INTFMT, _value);
-		return buffer;
+		return XS_String(buffer);
 	}
 
 protected:
@@ -1869,7 +2008,7 @@
 	{
 		LPTSTR end;
 
-		if (value && *value)
+		if (value && *value)//@@ also handle white space and return def instead of 0
 			_value = XS_tod(value, &end);
 		else
 			_value = def;
@@ -1895,7 +2034,7 @@
 	{
 		XS_CHAR buffer[32];
 		XS_snprintf(buffer, COUNTOF(buffer), XS_FLOATFMT, _value);
-		return buffer;
+		return XS_String(buffer);
 	}
 
 protected:
@@ -2022,6 +2161,7 @@
 };
 
 
+ // read option (for example configuration) values from XML node attributes
 template<typename T>
 	inline void read_option(T& var, const_XMLPos& cfg, LPCXSSTR key)
 	{
@@ -2031,6 +2171,7 @@
 			var = val;
 	}
 
+ // read integer option values from XML node attributes
 template<>
 	inline void read_option(int& var, const_XMLPos& cfg, LPCXSSTR key)
 	{
@@ -2039,6 +2180,141 @@
 		if (!val.empty())
 			var = XS_toi(val.c_str());
 	}
+
+
+inline void XMLPos::set_property(const XS_String& key, int value, const XS_String& name)
+{
+	smart_create(name, XS_KEY, key);
+		XMLIntRef(_cur, XS_VALUE) = value;
+	back();
+}
+
+inline void XMLPos::set_property(const XS_String& key, double value, const XS_String& name)
+{
+	smart_create(name, XS_KEY, key);
+		XMLDoubleRef(_cur, XS_VALUE) = value;
+	back();
+}
+
+inline void XMLPos::set_property(const XS_String& key, const XS_String& value, const XS_String& name)
+{
+	smart_create(name, XS_KEY, key);
+		put(XS_VALUE, value);
+	back();
+}
+
+inline void XMLPos::set_property(const XS_String& key, const XMLBool& value, const XS_String& name)
+{
+	smart_create(name, XS_KEY, key);
+		XMLBoolRef(_cur, XS_VALUE) = value;
+	back();
+}
+
+
+ /// a key/value pair for property data access
+struct XMLProperty {
+	XMLProperty(const XMLNode* node)
+	 :	_key(node->get(XS_KEY)),
+		_value(node->get(XS_VALUE))
+	{
+	}
+
+	XS_String	_key;
+	XS_String	_value;
+};
+
+
+ /// utility class to read property settings from a XML tree
+struct XMLPropertyReader
+{
+	XMLPropertyReader(const XMLNode::Children& children)
+	 :	_filter(children, XS_PROPERTY),
+		_begin(_filter.begin(), _filter.end()),
+		_end(_filter.end(), _filter.end())
+	{
+	}
+
+	XMLPropertyReader(const XMLNode* node)
+	 :	_filter(node, XS_PROPERTY),
+		_begin(_filter.begin(), _filter.end()),
+		_end(_filter.end(), _filter.end())
+	{
+	}
+
+	 /// internal iterator class
+	struct const_iterator
+	{
+		typedef const_XMLChildrenFilter::const_iterator BaseIterator;
+		typedef const_iterator myType;
+
+		const_iterator(BaseIterator begin, BaseIterator end)
+		 :	_cur(begin),
+			_end(end)
+		{
+		}
+
+		operator BaseIterator()
+		{
+			return _cur;
+		}
+
+		XMLProperty operator*() const
+		{
+			return XMLProperty(*_cur);
+		}
+
+		const XMLNode* get_node() const
+		{
+			return *_cur;
+		}
+
+		myType& operator++()
+		{
+			++_cur;
+
+			return *this;
+		}
+
+		myType operator++(int)
+		{
+			myType ret = *this;
+
+			++_cur;
+
+			return ret;
+		}
+
+		bool operator==(const myType& other) const
+		{
+			return _cur == other._cur;
+		}
+
+		bool operator!=(const myType& other) const
+		{
+			return _cur != other._cur;
+		}
+
+	protected:
+		BaseIterator	_cur;
+		BaseIterator	_end;
+	};
+
+	const_iterator begin()
+	{
+		return _begin;
+	}
+
+	const_iterator end()
+	{
+		return _end;
+	}
+
+protected:
+	const_XMLChildrenFilter	_filter;
+
+	const_iterator	_begin;
+	const_iterator	_end;
+};
 
 
 #ifdef _MSC_VER
@@ -2245,7 +2521,7 @@
 	typedef std::char_traits<_E> _Tr;
 
 	explicit fast_ostringbuffer()
-		{_Init(0, 0, /*std::_Noread*/4);}	// optimized for ios::out mode
+		{_Init(0, 0, std::_Noread);}	// optimized for ios::out mode
 
 	virtual ~fast_ostringbuffer()
 		{_Tidy();}
@@ -2274,10 +2550,10 @@
 			else if (_ALSIZE < _Alsize)
 				_Alsize = _ALSIZE;
 
-			if (_Strmode & std::strstreambuf::_Allocated)
+			if (_Strmode & std::_Allocated)
 				_Al.deallocate(eback(), _Os);
 
-			_Strmode |= std::strstreambuf::_Allocated;
+			_Strmode |= std::_Allocated;
 
 			if (_Os == 0)
 				{_Seekhigh = _P;
@@ -2291,24 +2567,24 @@
 
 			return _C;}}
 
-	void _Init(const _E *_S, size_t _N, std::strstreambuf::_Strstate _M)
+	void _Init(const _E *_S, size_t _N, std::_Strstate _M)
 		{_Pendsave = 0, _Seekhigh = 0;
 		_Alsize = _MINSIZE, _Strmode = _M;
 		setg(0, 0, 0);
 		setp(0, 0);}
 
 	void _Tidy()
-		{if (_Strmode & std::strstreambuf::_Allocated)
+		{if (_Strmode & std::_Allocated)
 			_Al.deallocate(eback(), (pptr() != 0 ? epptr() : egptr()) - eback());
 		_Seekhigh = 0;
-		_Strmode &= ~std::strstreambuf::_Allocated;}
+		_Strmode &= ~std::_Allocated;}
 
 private:
 	enum {_ALSIZE = 65536/*512*/, _MINSIZE = 32768/*32*/};	// bigger buffer sizes
 
 	_E *_Pendsave, *_Seekhigh;
 	int _Alsize;
-	std::strstreambuf::_Strstate _Strmode;
+	std::_Strstate _Strmode;
 	std::allocator<_E> _Al;
 };
 
@@ -2545,37 +2821,10 @@
 	}
 
 	 /// create node and move to it
-	void create(const XS_String& name)
-	{
-		if (!_stack.empty()) {
-			StackEntry& last = _stack.top();
-
-			if (last._state < PRE_CLOSED) {
-				write_attributes(last);
-				close_pre(last);
-			}
-
-			++last._children;
-		}
-
-		StackEntry entry;
-		entry._node_name = name;
-		_stack.push(entry);
-
-		write_pre(entry);
-	}
+	void create(const XS_String& name);
 
 	 /// go back to previous position
-	bool back()
-	{
-		if (!_stack.empty()) {
-			write_post(_stack.top());
-
-			_stack.pop();
-			return true;
-		} else
-			return false;
-	}
+	bool back();
 
 	 /// attribute setting
 	void put(const XS_String& attr_name, const XS_String& value)
@@ -2626,62 +2875,10 @@
 
 	static XS_String s_empty_attr;
 
-	void close_pre(StackEntry& entry)
-	{
-		_out << '>';
-
-		entry._state = PRE_CLOSED;
-	}
-
-	void write_pre(StackEntry& entry)
-	{
-		if (_format._pretty >= PRETTY_LINEFEED)
-			_out << _format._endl;
-
-		if (_format._pretty == PRETTY_INDENT)
-		{
-			for(size_t i=_stack.size(); --i>0; )
-				_out << XML_INDENT_SPACE;
-		}
-		_out << '<' << EncodeXMLString(entry._node_name);
-		//entry._state = PRE;
-	}
-
-	void write_attributes(StackEntry& entry)
-	{
-		for(AttrMap::const_iterator it=entry._attributes.begin(); it!=entry._attributes.end(); ++it)
-			_out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\"";
-
-		entry._state = ATTRIBUTES;
-	}
-
-	void write_post(StackEntry& entry)
-	{
-		if (entry._state < ATTRIBUTES)
-			write_attributes(entry);
-
-		if (entry._children || !entry._content.empty()) {
-			if (entry._state < PRE_CLOSED)
-				close_pre(entry);
-
-			_out << entry._content;
-			//entry._state = CONTENT;
-
-			if (_format._pretty>=PRETTY_LINEFEED && entry._content.empty())
-				_out << _format._endl;
-
-			if (_format._pretty==PRETTY_INDENT && entry._content.empty())
-			{
-				for(size_t i=_stack.size(); --i>0; )
-					_out << XML_INDENT_SPACE;
-			}
-			_out << "</" << EncodeXMLString(entry._node_name) << ">";
-		} else {
-			_out << "/>";
-		}
-
-		entry._state = POST;
-	}
+	void close_pre(StackEntry& entry);
+	void write_pre(StackEntry& entry);
+	void write_attributes(StackEntry& entry);
+	void write_post(StackEntry& entry);
 };
 
 

Modified: trunk/reactos/base/shell/explorer/utility/xs-native.cpp
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/explorer/utility/xs-native.cpp?rev=33226&r1=33225&r2=33226&view=diff
==============================================================================
--- trunk/reactos/base/shell/explorer/utility/xs-native.cpp [iso-8859-1] (original)
+++ trunk/reactos/base/shell/explorer/utility/xs-native.cpp [iso-8859-1] Thu May  1 16:17:35 2008
@@ -1,8 +1,8 @@
 
  //
- // XML storage C++ classes version 1.2
+ // XML storage C++ classes version 1.3
  //
- // Copyright (c) 2006, 2007 Martin Fuchs <martin-fuchs at gmx.net>
+ // Copyright (c) 2006, 2007, 2008 Martin Fuchs <martin-fuchs at gmx.net>
  //
 
  /// \file xs-native.cpp
@@ -94,7 +94,7 @@
 		_buffer_str.erase();
 	}
 
-	void append(char c)
+	void append(int c)
 	{
 		size_t wpos = _wptr-_buffer;
 
@@ -104,7 +104,7 @@
 			_wptr = _buffer + wpos;
 		}
 
-		*_wptr++ = c;
+		*_wptr++ = static_cast<char>(c);
 	}
 
 	const std::string& str(bool utf8)	// returns UTF-8 encoded buffer content
@@ -149,8 +149,7 @@
 		if (*q == '?')
 			++q;
 
-		while(isxmlsym(*q))
-			++q;
+		q = get_xmlsym_end_utf8(q);
 
 #ifdef XS_STRING_UTF8
 		return XS_String(p, q-p);
@@ -175,8 +174,7 @@
 		else if (*p == '?')
 			++p;
 
-		while(isxmlsym(*p))
-			++p;
+		p = get_xmlsym_end_utf8(p);
 
 		 // read attributes from buffer
 		while(*p && *p!='>' && *p!='/') {
@@ -185,8 +183,7 @@
 
 			const char* attr_name = p;
 
-			while(isxmlsym(*p))
-				++p;
+			p = get_xmlsym_end_utf8(p);
 
 			if (*p != '=')
 				break;	//@TODO error handling
@@ -360,8 +357,7 @@
 			 // read white space
 			for(;;) {
 				 // check for the encoding of the first line end
-				if (!_endl_defined)
-				{
+				if (!_endl_defined) {
 					if (c == '\n') {
 						_format._endl = "\n";
 						_endl_defined = true;
@@ -370,6 +366,7 @@
 						_endl_defined = true;
 					}
 				}
+
 				c = get();
 
 				if (c == EOF)



More information about the Ros-diffs mailing list