diff --git a/repos/base/include/util/xml_node.h b/repos/base/include/util/xml_node.h
index c4ca51e904..75de241183 100644
--- a/repos/base/include/util/xml_node.h
+++ b/repos/base/include/util/xml_node.h
@@ -14,6 +14,7 @@
#ifndef _INCLUDE__UTIL__XML_NODE_H_
#define _INCLUDE__UTIL__XML_NODE_H_
+#include
#include
#include
@@ -45,8 +46,22 @@ class Genode::Xml_attribute
*/
typedef ::Genode::Token Token;
- Token _name;
- Token _value;
+ struct Tokens
+ {
+ Token name;
+ Token value;
+
+ Tokens(Token t)
+ : name(t.eat_whitespace()), value(name.next().next()) { };
+
+ bool valid() const
+ {
+ bool const tag_present = (name.type() == Token::IDENT);
+ bool const value_present = (name.next()[0] == '=' &&
+ value.type() == Token::STRING);
+ return tag_present && value_present;
+ }
+ } _tokens;
friend class Xml_node;
@@ -58,6 +73,11 @@ class Genode::Xml_attribute
*/
friend class Tag;
+ /**
+ * Return true if token refers to a valid attribute
+ */
+ static bool _valid(Token t) { return Tokens(t).valid(); }
+
/**
* Constructor
*
@@ -65,20 +85,19 @@ class Genode::Xml_attribute
* construct an 'Xml_attribute' from a token sequence via an
* assignment from the leading 'Token'.
*/
- Xml_attribute(Token t) :
- _name(t.eat_whitespace()), _value(_name.next().next())
+ explicit Xml_attribute(Token t) : _tokens(t)
{
- if (_name.type() != Token::IDENT)
+ if (_tokens.name.type() != Token::IDENT)
throw Nonexistent_attribute();
- if (_name.next()[0] != '=' || _value.type() != Token::STRING)
+ if (!_tokens.valid())
throw Invalid_syntax();
}
/**
* Return token following the attribute declaration
*/
- Token _next() const { return _name.next().next().next(); }
+ Token _next_token() const { return _tokens.name.next().next().next(); }
public:
@@ -102,20 +121,20 @@ class Genode::Xml_attribute
* Limit number of characters by token length, take
* null-termination into account.
*/
- max_len = min(max_len, _name.len() + 1);
- strncpy(dst, _name.start(), max_len);
+ max_len = min(max_len, _tokens.name.len() + 1);
+ strncpy(dst, _tokens.name.start(), max_len);
}
typedef String<64> Name;
Name name() const {
- return Name(Cstring(_name.start(), _name.len())); }
+ return Name(Cstring(_tokens.name.start(), _tokens.name.len())); }
/**
* Return true if attribute has specified type
*/
bool has_type(char const *type) {
- return strlen(type) == _name.len() &&
- strcmp(type, _name.start(), _name.len()) == 0; }
+ return strlen(type) == _tokens.name.len() &&
+ strcmp(type, _tokens.name.start(), _tokens.name.len()) == 0; }
/**
* Return size of value
@@ -123,7 +142,7 @@ class Genode::Xml_attribute
* \deprecated use 'with_raw_node' instead
* \noapi
*/
- char const *value_base() const { return _value.start() + 1; }
+ char const *value_base() const { return _tokens.value.start() + 1; }
/**
* Return size of the value in bytes
@@ -137,15 +156,15 @@ class Genode::Xml_attribute
* The invariant 'len >= 2' is enforced by the 'Xml_attribute'
* constructor by checking the '_value' type for being a 'STRING'.
*/
- return _value.len() - 2;
+ return _tokens.value.len() - 2;
}
/**
* Return true if attribute has the specified value
*/
bool has_value(char const *value) const {
- return strlen(value) == (_value.len() - 2)
- && !strcmp(value, _value.start() + 1, _value.len() - 2); }
+ return strlen(value) == (_tokens.value.len() - 2)
+ && !strcmp(value, _tokens.value.start() + 1, _tokens.value.len() - 2); }
/**
* Call functor 'fn' with the data of the attribute value as argument
@@ -162,7 +181,7 @@ class Genode::Xml_attribute
/*
* Skip leading quote of the '_value' to access the actual value.
*/
- fn(_value.start() + 1, value_size());
+ fn(_tokens.value.start() + 1, value_size());
}
/**
@@ -239,7 +258,7 @@ class Genode::Xml_attribute
/**
* Return next attribute in attribute list
*/
- Xml_attribute next() const { return Xml_attribute(_next()); }
+ Xml_attribute next() const { return Xml_attribute(_next_token()); }
};
@@ -325,10 +344,8 @@ class Genode::Xml_node
/* skip attributes to find tag delimiter */
Token delimiter = _name.next();
if (supposed_type != END)
- try {
- for (Xml_attribute a = _name.next(); ; a = a._next())
- delimiter = a._next();
- } catch (Nonexistent_attribute) { }
+ while (Xml_attribute::_valid(delimiter))
+ delimiter = Xml_attribute(delimiter)._next_token();
delimiter = delimiter.eat_whitespace();
@@ -395,6 +412,11 @@ class Genode::Xml_node
return t.next();
}
+ /**
+ * Return true if tag as at least one attribute
+ */
+ bool has_attribute() const { return Xml_attribute::_valid(_name.next()); }
+
/**
* Return first attribute of tag
*/
@@ -505,12 +527,8 @@ class Genode::Xml_node
}
};
- int _num_sub_nodes { 0 }; /* number of immediate sub nodes */
-
char const * _addr; /* first character of XML data */
size_t _max_len; /* length of XML data in characters */
- Tag _start_tag;
- Tag _end_tag;
/**
* Search matching end tag for given start tag and detemine number of
@@ -611,15 +629,49 @@ class Genode::Xml_node
return t;
}
+ struct Tags
+ {
+ int num_sub_nodes = 0;
+ Tag start;
+ Tag end;
+
+ Tags(char const *addr, size_t max_len)
+ :
+ start(skip_non_tag_characters(Token(addr, max_len))),
+ end(_search_end_tag(start, num_sub_nodes))
+ { }
+ } _tags;
+
+ /**
+ * Return true if specified buffer contains a valid XML node
+ */
+ static bool _valid(Tags const &tags)
+ {
+ if (tags.start.type() == Tag::EMPTY)
+ return true;
+
+ if (tags.start.type() == Tag::START && tags.end.type() == Tag::END)
+ return true;
+
+ return false;
+ }
+
+ bool _valid_node_at(char const *at) const
+ {
+ bool const in_range = (at >= _addr && (size_t)(at - _addr) < _max_len);
+
+ return in_range && _valid(Tags(at, _max_len - (at - _addr)));
+ }
+
/**
* Create sub node from XML node
*
* \throw Nonexistent_sub_node
* \throw Invalid_syntax
*/
- Xml_node _sub_node(char const *at) const
+ Xml_node _node_at(char const *at) const
{
- if (at < _addr || (size_t)(at - _addr) >= _max_len)
+ if (!_valid_node_at(at))
throw Nonexistent_sub_node();
return Xml_node(at, _max_len - (at - _addr));
@@ -628,7 +680,7 @@ class Genode::Xml_node
/**
* Return pointer to start of content
*/
- char const *_content_base() const { return _start_tag.next_token().start(); }
+ char const *_content_base() const { return _tags.start.next_token().start(); }
public:
@@ -642,16 +694,10 @@ class Genode::Xml_node
*/
Xml_node(char const *addr, size_t max_len = ~0UL)
:
- _addr(addr),
- _max_len(max_len),
- _start_tag(skip_non_tag_characters(Token(addr, max_len))),
- _end_tag(_search_end_tag(_start_tag, _num_sub_nodes))
+ _addr(addr), _max_len(max_len), _tags(addr, max_len)
{
- /* check validity of XML node */
- if (_start_tag.type() == Tag::EMPTY) return;
- if (_start_tag.type() == Tag::START && _end_tag.type() == Tag::END) return;
-
- throw Invalid_syntax();
+ if (!_valid(_tags))
+ throw Invalid_syntax();
}
/**
@@ -660,12 +706,12 @@ class Genode::Xml_node
* \noapi
*/
void type_name(char *dst, size_t max_len) const {
- _start_tag.name().string(dst, max_len); }
+ _tags.start.name().string(dst, max_len); }
/**
* Return size of node including start and end tags in bytes
*/
- size_t size() const { return _end_tag.next_token().start() - _addr; }
+ size_t size() const { return _tags.end.next_token().start() - _addr; }
/**
* Return pointer to start of node
@@ -680,10 +726,10 @@ class Genode::Xml_node
*/
size_t content_size() const
{
- if (_start_tag.type() == Tag::EMPTY)
+ if (_tags.start.type() == Tag::EMPTY)
return 0;
- return _end_tag.token().start() - _content_base();
+ return _tags.end.token().start() - _content_base();
}
/**
@@ -692,7 +738,7 @@ class Genode::Xml_node
typedef String<64> Type;
Type type() const
{
- Token name = _start_tag.name();
+ Token name = _tags.start.name();
return Type(Cstring(name.start(), name.len()));
}
@@ -700,9 +746,9 @@ class Genode::Xml_node
* Return true if tag is of specified type
*/
bool has_type(char const *type) const {
- return (!strcmp(type, _start_tag.name().start(),
- _start_tag.name().len())
- && strlen(type) == _start_tag.name().len()); }
+ return (!strcmp(type, _tags.start.name().start(),
+ _tags.start.name().len())
+ && strlen(type) == _tags.start.name().len()); }
/**
* Call functor 'fn' with the node data '(char const *, size_t)'
@@ -710,7 +756,7 @@ class Genode::Xml_node
template
void with_raw_node(FN const &fn) const
{
- fn(_addr, _end_tag.next_token().start() - _addr);
+ fn(_addr, _tags.end.next_token().start() - _addr);
}
/**
@@ -724,7 +770,7 @@ class Genode::Xml_node
template
void with_raw_content(FN const &fn) const
{
- if (_start_tag.type() == Tag::EMPTY)
+ if (_tags.start.type() == Tag::EMPTY)
return;
fn(_content_base(), content_size());
@@ -737,7 +783,7 @@ class Genode::Xml_node
*
* \noapi
*/
- char *content_addr() const { return _start_tag.next_token().start(); }
+ char *content_addr() const { return _tags.start.next_token().start(); }
/**
* Return pointer to start of content
@@ -792,7 +838,7 @@ class Genode::Xml_node
/**
* Return the number of the XML node's immediate sub nodes
*/
- size_t num_sub_nodes() const { return _num_sub_nodes; }
+ size_t num_sub_nodes() const { return _tags.num_sub_nodes; }
/**
* Return XML node following the current one
@@ -801,9 +847,11 @@ class Genode::Xml_node
*/
Xml_node next() const
{
- Token after_node = _end_tag.next_token();
+ Token after_node = _tags.end.next_token();
after_node = skip_non_tag_characters(after_node);
- try { return _sub_node(after_node.start()); }
+ try {
+ return _node_at(after_node.start());
+ }
catch (Invalid_syntax) { throw Nonexistent_sub_node(); }
}
@@ -824,10 +872,22 @@ class Genode::Xml_node
/**
* Return true if node is the last of a node sequence
*/
- bool last(char const *type = 0) const
+ bool last(char const *type = nullptr) const
{
- try { next(type); return false; }
- catch (Nonexistent_sub_node) { return true; }
+ Token after = _tags.end.next_token();
+ after = skip_non_tag_characters(after);
+
+ for (;;) {
+ if (!_valid_node_at(after.start()))
+ return true;
+
+ Xml_node node = _node_at(after.start());
+ if (!type || node.has_type(type))
+ return false;
+
+ after = node._tags.end.next_token();
+ after = skip_non_tag_characters(after);
+ }
}
/**
@@ -839,17 +899,14 @@ class Genode::Xml_node
*/
Xml_node sub_node(unsigned idx = 0U) const
{
- if (_num_sub_nodes > 0) {
-
- /* look up node at specified index */
+ if (_tags.num_sub_nodes > 0) {
try {
- Xml_node curr_node = _sub_node(_content_base());
+ Xml_node curr_node = _node_at(_content_base());
for (; idx > 0; idx--)
curr_node = curr_node.next();
return curr_node;
} catch (Invalid_syntax) { }
}
-
throw Nonexistent_sub_node();
}
@@ -860,17 +917,16 @@ class Genode::Xml_node
*/
Xml_node sub_node(char const *type) const
{
- if (_num_sub_nodes > 0) {
+ if (_tags.num_sub_nodes > 0) {
/* search for sub node of specified type */
try {
- Xml_node curr_node = _sub_node(_content_base());
+ Xml_node curr_node = _node_at(_content_base());
for ( ; true; curr_node = curr_node.next())
- if (curr_node.has_type(type))
+ if (!type || curr_node.has_type(type))
return curr_node;
} catch (...) { }
}
-
throw Nonexistent_sub_node();
}
@@ -893,20 +949,16 @@ class Genode::Xml_node
template
void for_each_sub_node(char const *type, FN const &fn) const
{
- if (_num_sub_nodes == 0)
+ if (!has_sub_node(type))
return;
- try {
- Xml_node node = sub_node();
- for (int i = 0; ; node = node.next()) {
+ for (Xml_node node = sub_node(type); ; node = node.next()) {
+ if (!type || node.has_type(type))
+ fn(node);
- if (!type || node.has_type(type))
- fn(node);
-
- if (++i == _num_sub_nodes)
- break;
- }
- } catch (Nonexistent_sub_node) { }
+ if (node.last())
+ break;
+ }
}
/**
@@ -928,14 +980,11 @@ class Genode::Xml_node
*/
Xml_attribute attribute(unsigned idx) const
{
- /* get first attribute of the node */
- Xml_attribute a = _start_tag.attribute();
+ Xml_attribute attr = _tags.start.attribute();
+ for (unsigned i = 0; i < idx; i++)
+ attr = Xml_attribute(attr._next_token());
- /* skip attributes until we reach the target index */
- for (; idx > 0; idx--)
- a = a._next();
-
- return a;
+ return attr;
}
/**
@@ -947,10 +996,13 @@ class Genode::Xml_node
*/
Xml_attribute attribute(char const *type) const
{
- /* iterate, beginning with the first attribute of the node */
- for (Xml_attribute a = _start_tag.attribute(); ; a = a.next())
- if (a.has_type(type))
- return a;
+ for (Xml_attribute attr = _tags.start.attribute(); ;) {
+ if (attr.has_type(type))
+ return attr;
+
+ attr = Xml_attribute(attr._next_token());
+ }
+ throw Nonexistent_attribute();
}
/**
@@ -968,7 +1020,27 @@ class Genode::Xml_node
inline T attribute_value(char const *type, T const default_value) const
{
T result = default_value;
- try { attribute(type).value(result); } catch (...) { }
+
+ if (!_tags.start.has_attribute())
+ return result;
+
+ for (Xml_attribute attr = _tags.start.attribute(); ; ) {
+
+ /* match */
+ if (attr.has_type(type)) {
+ attr.value(result);
+ return result;
+ }
+
+ /* end of attribute */
+ Token const next = attr._next_token();
+ if (!Xml_attribute::_valid(next))
+ break;
+
+ /* keep searching */
+ attr = Xml_attribute(next);
+ }
+
return result;
}
@@ -977,16 +1049,46 @@ class Genode::Xml_node
*/
inline bool has_attribute(char const *type) const
{
- try { attribute(type); return true; } catch (...) { }
- return false;
+ if (!_tags.start.has_attribute())
+ return false;
+
+ if (type == nullptr)
+ return true;
+
+ for (Xml_attribute attr = _tags.start.attribute(); ; ) {
+ if (attr.has_type(type))
+ return true;
+
+ Token const next = attr._next_token();
+ if (!Xml_attribute::_valid(next))
+ return false;
+
+ attr = Xml_attribute(next);
+ }
}
/**
* Return true if sub node of specified type exists
*/
- inline bool has_sub_node(char const *type) const
+ bool has_sub_node(char const *type) const
{
- try { sub_node(type); return true; } catch (...) { }
+ if (_tags.num_sub_nodes == 0)
+ return false;
+
+ if (!_valid_node_at(_content_base()))
+ return false;
+
+ if (type == nullptr)
+ return true;
+
+ /* search for node of given type */
+ for (Xml_node node = _node_at(_content_base()); ; node = node.next()) {
+ if (node.has_type(type))
+ return true;
+
+ if (node.last())
+ break;
+ }
return false;
}