From 5cfce75c9ad4d250af20f5bdc0d10def3b0c28d9 Mon Sep 17 00:00:00 2001 From: Martin Fuchs Date: Thu, 1 May 2008 21:17:35 +0000 Subject: [PATCH] update to XMLStorage version 1.3 svn path=/trunk/; revision=33226 --- .../shell/explorer/utility/xmlstorage.cpp | 392 ++++++++--- .../base/shell/explorer/utility/xmlstorage.h | 631 ++++++++++++------ .../base/shell/explorer/utility/xs-native.cpp | 21 +- 3 files changed, 731 insertions(+), 313 deletions(-) diff --git a/reactos/base/shell/explorer/utility/xmlstorage.cpp b/reactos/base/shell/explorer/utility/xmlstorage.cpp index f82dffb5815..3dba1ba0fbf 100644 --- a/reactos/base/shell/explorer/utility/xmlstorage.cpp +++ b/reactos/base/shell/explorer/utility/xmlstorage.cpp @@ -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 + // Copyright (c) 2004, 2005, 2006, 2007, 2008 Martin Fuchs // /// \file xmlstorage.cpp @@ -57,6 +57,10 @@ const LPCXSSTR XS_INTFMT = XS_INTFMT_STR; 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 @@ inline std::string unescape(const char* s, size_t l) } - /// move XPath like to position in XML tree -bool XMLPos::go(const char* path) + /// move to the position defined by xpath in XML tree +bool XMLPos::go(const XPath& xpath) { - XMLNode* node = _cur; + XMLNode* node = xpath._absolute? _root: _cur; - // Is this an absolute path? - if (*path == '/') { - node = _root; - ++path; - } - - node = node->find_relative(path); + node = node->find_relative(xpath); if (node) { go_to(node); @@ -125,18 +123,12 @@ bool XMLPos::go(const char* path) return false; } - /// move XPath like to position in XML tree -bool const_XMLPos::go(const char* path) + /// move to the position defined by xpath in XML tree +bool const_XMLPos::go(const XPath& xpath) { - const XMLNode* node = _cur; + const XMLNode* node = xpath._absolute? _root: _cur; - // Is this an absolute path? - if (*path == '/') { - node = _root; - ++path; - } - - node = node->find_relative(path); + node = node->find_relative(xpath); if (node) { go_to(node); @@ -146,40 +138,7 @@ bool const_XMLPos::go(const char* path) } -const XMLNode* XMLNode::find_relative(const char* path) const -{ - const XMLNode* node = this; - - // parse relative path - while(*path) { - node = const_cast(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 @@ XMLNode* XMLNode::get_child_relative(const char*& path, bool create) // 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 @@ XMLNode* XMLNode::get_child_relative(const char*& path, bool create) 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 @@ XMLNode* XMLNode::get_child_relative(const char*& path, bool create) // 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; + return path; +} - if (attr_name.empty()) - // search n.th child node with specified name - child = find(child_name, n); +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); + return false; +} - if (!child && create) { - child = new XMLNode(child_name); - add_child(child); - if (!attr_name.empty()) - (*this)[attr_name] = attr_value; +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 child; + 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 @@ std::string EncodeXMLString(const XS_String& str, bool cdata) 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 @@ std::string EncodeXMLString(const XS_String& str, bool cdata) 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 @@ XS_String DecodeXMLString(const XS_String& str) } 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 @@ std::ostream& operator<<(std::ostream& out, const XMLError& err) } +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 @@ void XMLReaderBase::StartElementHandler(const XS_String& name, const XMLNode::At 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 @@ void XMLReaderBase::StartElementHandler(const XS_String& name, const XMLNode::At p = s; } else _pos->_children.back()->_trailing.append(s, p-s); - } + std::string leading; if (p != e) @@ -753,14 +893,12 @@ void XMLReaderBase::EndElementHandler() } 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 @@ void XMLReaderBase::DefaultHandler(const XML_Char* s, int len) 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 << ""; + } else { + _out << "/>"; + } + + entry._state = POST; +} + } // namespace XMLStorage diff --git a/reactos/base/shell/explorer/utility/xmlstorage.h b/reactos/base/shell/explorer/utility/xmlstorage.h index 3f43c129b8f..b16ef9093f4 100644 --- a/reactos/base/shell/explorer/utility/xmlstorage.h +++ b/reactos/base/shell/explorer/utility/xmlstorage.h @@ -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 + // Copyright (c) 2004, 2005, 2006, 2007, 2008 Martin Fuchs // /// \file xmlstorage.h @@ -39,9 +39,6 @@ #ifndef _XMLSTORAGE_H -#ifndef __REACTOS__ -#include -#endif #ifdef UNICODE #ifndef _UNICODE @@ -204,6 +201,10 @@ typedef const CHAR* LPCTSTR; #endif +#ifdef __BORLANDC__ +#define _stricmp stricmp +#endif + #include #include @@ -264,10 +265,7 @@ namespace XMLStorage { #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 @@ struct XS_String #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 @@ extern const LPCXSSTR XS_FLOATFMT; #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 @@ enum WRITE_MODE { }; +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 +{ + 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 @@ struct XMLNode : public XS_String /// internal children node list struct Children : public std::list { - void assign(const Children& other) + typedef std::list 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)); } @@ -859,12 +935,30 @@ struct XMLNode : public XS_String 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(); + } }; // access to protected class members for XMLPos and XMLReader 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 @@ struct XMLNode : public XS_String _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 @@ struct XMLNode : public XS_String XMLNode& operator=(const XMLNode& other) { - _children.assign(other._children); + _children.clear(); + _children.copy(other._children); _attributes = other._attributes; @@ -933,6 +1044,16 @@ struct XMLNode : public XS_String _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 @@ struct XMLNode : public XS_String return def; } - /// convenient value access in children node - XS_String subvalue(const XS_String& name, const XS_String& attr_name, int n=0) const + /// remove the attribute 'attr_name' + void erase(const XS_String& attr_name) { - const XMLNode* node = find(name, n); + _attributes.erase(attr_name); + } + + /// convenient value access in children node + 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 @@ struct XMLNode : public XS_String } /// convenient storage of distinct values in children node - XS_String& subvalue(const XS_String& name, const XS_String& attr_name, int n=0) + XS_String& subvalue(const XS_String& child_name, const XS_String& attr_name, int n=0) { - XMLNode* node = find(name, n); + 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 @@ struct XMLNode : public XS_String #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 + XS_String subvalue(const char* child_name, const char* attr_name, int n=0) const { - const XMLNode* node = find(name, n); + const XMLNode* node = XPathElement(child_name, n).const_find(this); if (node) return node->get(attr_name); @@ -993,12 +1120,12 @@ struct XMLNode : public XS_String } /// convenient storage of distinct values in children node - XS_String& subvalue(const char* name, const XS_String& attr_name, int n=0) + XS_String& subvalue(const char* child_name, const XS_String& attr_name, int n=0) { - XMLNode* node = find(name, n); + 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 @@ struct XMLNode : public XS_String 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 @@ protected: 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 - 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(const_cast(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 XMLChildrenFilter 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 @@ struct XMLChildrenFilter return *_cur; } - iterator& operator++() + myType& operator++() { ++_cur; search_next(); @@ -1211,9 +1301,9 @@ struct XMLChildrenFilter return *this; } - iterator operator++(int) + myType operator++(int) { - iterator ret = *this; + myType ret = *this; ++_cur; search_next(); @@ -1221,14 +1311,14 @@ struct XMLChildrenFilter return ret; } - bool operator==(const BaseIterator& other) const + bool operator==(const myType& other) const { - return _cur == other; + return _cur == other._cur; } - bool operator!=(const BaseIterator& other) const + bool operator!=(const myType& other) const { - return _cur != other; + return _cur != other._cur; } protected: @@ -1278,6 +1368,7 @@ struct const_XMLChildrenFilter 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 @@ struct const_XMLChildrenFilter return *_cur; } - const_iterator& operator++() + myType& operator++() { ++_cur; search_next(); @@ -1305,9 +1396,9 @@ struct const_XMLChildrenFilter return *this; } - const_iterator operator++(int) + myType operator++(int) { - const_iterator ret = *this; + myType ret = *this; ++_cur; search_next(); @@ -1315,14 +1406,14 @@ struct const_XMLChildrenFilter return ret; } - bool operator==(const BaseIterator& other) const + bool operator==(const myType& other) const { - return _cur == other; + return _cur == other._cur; } - bool operator!=(const BaseIterator& other) const + bool operator!=(const myType& other) const { - return _cur != other; + return _cur != other._cur; } protected: @@ -1464,9 +1555,9 @@ struct XMLPos } /// search for child and go down - bool go_down(const XS_String& name, int n=0) + bool go_down(const XS_String& child_name, int n=0) { - XMLNode* node = _cur->find(name, n); + XMLNode* node = XPathElement(child_name, n).find(_cur); if (node) { go_to(node); @@ -1475,13 +1566,13 @@ struct XMLPos 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) + bool create_relative(const XPath& xpath) { - XMLNode* node = _cur->create_relative(path); + XMLNode* node = _cur->create_relative(xpath); if (!node) return false; // invalid path specified @@ -1496,35 +1587,47 @@ struct XMLPos } /// create node if not already existing and move to it - void smart_create(const XS_String& name) + void smart_create(const XS_String& child_name) { - XMLNode* node = _cur->find(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) + void smart_create(const XS_String& child_name, const XS_String& attr_name, const XS_String& attr_value) { - XMLNode* node = _cur->find(name, attr_name, 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) + bool go_down(const char* child_name, int n=0) { - XMLNode* node = _cur->find(name, n); + XMLNode* node = XPathElement(child_name, n).find(_cur); if (node) { go_to(node); @@ -1534,41 +1637,77 @@ struct XMLPos } /// create node and move to it - void create(const char* name) + void create(const char* child_name) { - add_down(new XMLNode(name)); + add_down(new XMLNode(child_name)); } /// create node if not already existing and move to it - void smart_create(const char* name) + void smart_create(const char* child_name) { - XMLNode* node = _cur->find(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 - void smart_create(const char* name, const T& attr_name, const U& attr_value) + void smart_create(const char* child_name, const T& attr_name, const U& attr_value) { - XMLNode* node = _cur->find(name, attr_name, 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; XMLNode* _cur; @@ -1644,9 +1783,9 @@ struct const_XMLPos } /// search for child and go down - bool go_down(const XS_String& name, int n=0) + bool go_down(const XS_String& child_name, int n=0) { - XMLNode* node = _cur->find(name, n); + const XMLNode* node = XPathElement(child_name, n).const_find(_cur); if (node) { go_to(node); @@ -1655,14 +1794,14 @@ struct const_XMLPos 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) + bool go_down(const char* child_name, int n=0) { - XMLNode* node = _cur->find(name, n); + const XMLNode* node = XPathElement(child_name, n).const_find(_cur); if (node) { go_to(node); @@ -1698,7 +1837,7 @@ struct XMLBool 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 @@ struct XMLInt 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 @@ struct XMLInt { XS_CHAR buffer[32]; XS_snprintf(buffer, COUNTOF(buffer), XS_INTFMT, _value); - return buffer; + return XS_String(buffer); } protected: @@ -1869,7 +2008,7 @@ struct XMLDouble { 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 @@ struct XMLDouble { XS_CHAR buffer[32]; XS_snprintf(buffer, COUNTOF(buffer), XS_FLOATFMT, _value); - return buffer; + return XS_String(buffer); } protected: @@ -2022,6 +2161,7 @@ protected: }; + // read option (for example configuration) values from XML node attributes template inline void read_option(T& var, const_XMLPos& cfg, LPCXSSTR key) { @@ -2031,6 +2171,7 @@ template var = val; } + // read integer option values from XML node attributes template<> inline void read_option(int& var, const_XMLPos& cfg, LPCXSSTR key) { @@ -2041,6 +2182,141 @@ template<> } +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 #pragma warning(disable: 4355) #endif @@ -2245,7 +2521,7 @@ struct fast_ostringbuffer : public std::streambuf 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 @@ protected: 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 @@ protected: 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 @@ struct XMLWriter } /// 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 @@ protected: static XS_String s_empty_attr; - void close_pre(StackEntry& entry) - { - _out << '>'; - - entry._state = PRE_CLOSED; - } - - void write_pre(StackEntry& entry) - { - if (_format._pretty >= PRETTY_LINEFEED) - _out << _format._endl; - - if (_format._pretty == PRETTY_INDENT) - { - for(size_t i=_stack.size(); --i>0; ) - _out << XML_INDENT_SPACE; - } - _out << '<' << EncodeXMLString(entry._node_name); - //entry._state = PRE; - } - - void write_attributes(StackEntry& entry) - { - for(AttrMap::const_iterator it=entry._attributes.begin(); it!=entry._attributes.end(); ++it) - _out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\""; - - entry._state = ATTRIBUTES; - } - - void write_post(StackEntry& entry) - { - if (entry._state < ATTRIBUTES) - write_attributes(entry); - - if (entry._children || !entry._content.empty()) { - if (entry._state < PRE_CLOSED) - close_pre(entry); - - _out << entry._content; - //entry._state = CONTENT; - - if (_format._pretty>=PRETTY_LINEFEED && entry._content.empty()) - _out << _format._endl; - - if (_format._pretty==PRETTY_INDENT && entry._content.empty()) - { - for(size_t i=_stack.size(); --i>0; ) - _out << XML_INDENT_SPACE; - } - _out << ""; - } else { - _out << "/>"; - } - - entry._state = POST; - } + void close_pre(StackEntry& entry); + void write_pre(StackEntry& entry); + void write_attributes(StackEntry& entry); + void write_post(StackEntry& entry); }; diff --git a/reactos/base/shell/explorer/utility/xs-native.cpp b/reactos/base/shell/explorer/utility/xs-native.cpp index 06971aa6564..7f56dd2813c 100644 --- a/reactos/base/shell/explorer/utility/xs-native.cpp +++ b/reactos/base/shell/explorer/utility/xs-native.cpp @@ -1,8 +1,8 @@ // - // XML storage C++ classes version 1.2 + // XML storage C++ classes version 1.3 // - // Copyright (c) 2006, 2007 Martin Fuchs + // Copyright (c) 2006, 2007, 2008 Martin Fuchs // /// \file xs-native.cpp @@ -94,7 +94,7 @@ struct Buffer _buffer_str.erase(); } - void append(char c) + void append(int c) { size_t wpos = _wptr-_buffer; @@ -104,7 +104,7 @@ struct Buffer _wptr = _buffer + wpos; } - *_wptr++ = c; + *_wptr++ = static_cast(c); } const std::string& str(bool utf8) // returns UTF-8 encoded buffer content @@ -149,8 +149,7 @@ struct Buffer 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 @@ struct Buffer 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 @@ struct Buffer 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 @@ bool XMLReaderBase::parse() // 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 @@ bool XMLReaderBase::parse() _endl_defined = true; } } + c = get(); if (c == EOF)