update to XMLStorage version 1.3
authorMartin Fuchs <martin-fuchs@gmx.net>
Thu, 1 May 2008 21:17:35 +0000 (21:17 +0000)
committerMartin Fuchs <martin-fuchs@gmx.net>
Thu, 1 May 2008 21:17:35 +0000 (21:17 +0000)
svn path=/trunk/; revision=33226

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

index f82dffb..3dba1ba 100644 (file)
@@ -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_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;
-
-        // Is this an absolute path?
-       if (*path == '/') {
-               node = _root;
-               ++path;
-       }
+       XMLNode* node = xpath._absolute? _root: _cur;
 
-       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<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 @@ 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;
+}
+
+XMLNode* XPathElement::find(XMLNode* node) const
+{
+       int n = 0;
 
-       if (attr_name.empty())
-                // search n.th child node with specified name
-               child = find(child_name, n);
+       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;
+}
+
+
+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);
+       }
+}
 
-       if (!child && create) {
-               child = new XMLNode(child_name);
-               add_child(child);
 
-               if (!attr_name.empty())
-                       (*this)[attr_name] = attr_value;
+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 << "</" << EncodeXMLString(entry._node_name) << ">";
+       } else {
+               _out << "/>";
+       }
+
+       entry._state = POST;
+}
+
 
 }      // namespace XMLStorage
index 3f43c12..b16ef90 100644 (file)
@@ -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
@@ -204,6 +201,10 @@ typedef const CHAR* LPCTSTR;
 
 #endif
 
+#ifdef __BORLANDC__
+#define _stricmp stricmp
+#endif
+
 
 #include <fstream>
 #include <sstream>
@@ -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<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 @@ struct XMLNode : public XS_String
         /// 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));
                }
@@ -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;
        }
 
+        /// 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
+       XS_String subvalue(const XS_String& child_name, const XS_String& 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);
@@ -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<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 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<typename T, typename U>
-       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<typename T>
        inline void read_option(T& var, const_XMLPos& cfg, LPCXSSTR key)
        {
@@ -2031,6 +2171,7 @@ template<typename T>
                        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 << "</" << 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);
 };
 
 
index 06971aa..7f56dd2 100644 (file)
@@ -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 @@ 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<char>(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)