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... ============================================================================== --- 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@gmx.net + // Copyright (c) 2004, 2005, 2006, 2007, 2008 Martin Fuchs martin-fuchs@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... ============================================================================== --- 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@gmx.net + // Copyright (c) 2004, 2005, 2006, 2007, 2008 Martin Fuchs martin-fuchs@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... ============================================================================== --- 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@gmx.net + // Copyright (c) 2006, 2007, 2008 Martin Fuchs martin-fuchs@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)