Xml_generator: fix exception handling in Node(...)

When the functor provided to the Node constructor throws an exception,
do revert all changes in reverse order. Previously, the changes made
to the parent node were not considered by the exception handler which
caused unnecessary characters to remain in the out buffer for each
reverted node.

Issue #2953
This commit is contained in:
Martin Stein 2018-09-07 11:20:13 +02:00 committed by Christian Helmuth
parent e88081a454
commit 85d589a49c
2 changed files with 27 additions and 4 deletions

View File

@ -60,6 +60,9 @@ class Genode::Xml_generator
_used += len; _used += len;
} }
void undo_append(size_t const len) {
_used = len < _used ? _used - len : 0; }
/** /**
* Append character * Append character
*/ */
@ -162,6 +165,8 @@ class Genode::Xml_generator
unsigned const _indent_level; unsigned const _indent_level;
Node * const _parent_node = 0; Node * const _parent_node = 0;
bool const _parent_was_indented;
bool const _parent_had_content;
Out_buffer _out_buffer; Out_buffer _out_buffer;
@ -197,6 +202,20 @@ class Genode::Xml_generator
return _out_buffer.remainder(); return _out_buffer.remainder();
} }
void _undo_content_buffer(bool indented,
bool was_indented,
bool had_content)
{
_is_indented = was_indented;
_has_content = had_content;
if (indented)
_out_buffer.undo_append(1);
if (!_has_content)
_out_buffer.undo_append(1);
}
/** /**
* Called by sub node * Called by sub node
*/ */
@ -241,6 +260,8 @@ class Genode::Xml_generator
: :
_indent_level(xml._curr_indent), _indent_level(xml._curr_indent),
_parent_node(xml._curr_node), _parent_node(xml._curr_node),
_parent_was_indented(_parent_node ? _parent_node->is_indented() : false),
_parent_had_content (_parent_node ? _parent_node->has_content() : false),
_out_buffer(_parent_node ? _parent_node->_content_buffer(true) _out_buffer(_parent_node ? _parent_node->_content_buffer(true)
: xml._out_buffer) : xml._out_buffer)
{ {
@ -261,6 +282,8 @@ class Genode::Xml_generator
/* reset and drop changes by not committing it */ /* reset and drop changes by not committing it */
xml._curr_node = _parent_node; xml._curr_node = _parent_node;
xml._curr_indent--; xml._curr_indent--;
if (_parent_node) {
_parent_node->_undo_content_buffer(true, _parent_was_indented, _parent_had_content); }
throw; throw;
} }
@ -286,6 +309,9 @@ class Genode::Xml_generator
_out_buffer.append('\0'); _out_buffer.append('\0');
} }
bool has_content() { return _has_content; }
bool is_indented() { return _is_indented; }
}; };
Out_buffer _out_buffer; Out_buffer _out_buffer;

View File

@ -53,20 +53,17 @@ compare_output_to {
[init -> test-xml_generator] exception on level3 (expected exception value=11) [init -> test-xml_generator] exception on level3 (expected exception value=11)
[init -> test-xml_generator] exception on level3 (expected exception value=12) [init -> test-xml_generator] exception on level3 (expected exception value=12)
[init -> test-xml_generator] [init -> test-xml_generator]
[init -> test-xml_generator] used 183 bytes, result: [init -> test-xml_generator] used 180 bytes, result:
[init -> test-xml_generator] [init -> test-xml_generator]
[init -> test-xml_generator] <config> [init -> test-xml_generator] <config>
[init -> test-xml_generator] <level1> [init -> test-xml_generator] <level1>
[init -> test-xml_generator] <level2> [init -> test-xml_generator] <level2>
[init -> test-xml_generator]
[init -> test-xml_generator] <level3> [init -> test-xml_generator] <level3>
[init -> test-xml_generator] <level4/> [init -> test-xml_generator] <level4/>
[init -> test-xml_generator] </level3> [init -> test-xml_generator] </level3>
[init -> test-xml_generator]
[init -> test-xml_generator] <level3> [init -> test-xml_generator] <level3>
[init -> test-xml_generator] <level4/> [init -> test-xml_generator] <level4/>
[init -> test-xml_generator] </level3> [init -> test-xml_generator] </level3>
[init -> test-xml_generator]
[init -> test-xml_generator] <level3> [init -> test-xml_generator] <level3>
[init -> test-xml_generator] <level4/> [init -> test-xml_generator] <level4/>
[init -> test-xml_generator] </level3> [init -> test-xml_generator] </level3>