os/buffered_xml.h: support for generating XML
This patch extends the 'Buffered_xml' utility with a new constructor that fills the buffer with the output of an 'Xml_generator'. It thereby presents an easy way to generate XML to be consumed locally. The patch also add a deprecation mark to the original 'xml' accessor because copying 'Xml_node' objects (here as return value) is dangerous. The new 'with_xml_node' method should instead be used to access the XML content stored in the buffer. Fixes #3602
This commit is contained in:
parent
640a001ab6
commit
f82e7df0ba
|
@ -15,7 +15,9 @@
|
||||||
#define _OS__BUFFERED_XML_H_
|
#define _OS__BUFFERED_XML_H_
|
||||||
|
|
||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
|
#include <util/retry.h>
|
||||||
#include <util/xml_node.h>
|
#include <util/xml_node.h>
|
||||||
|
#include <util/xml_generator.h>
|
||||||
#include <base/allocator.h>
|
#include <base/allocator.h>
|
||||||
|
|
||||||
namespace Genode { class Buffered_xml; }
|
namespace Genode { class Buffered_xml; }
|
||||||
|
@ -25,23 +27,51 @@ class Genode::Buffered_xml
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Allocator &_alloc;
|
Allocator &_alloc;
|
||||||
char const * const _ptr; /* pointer to dynamically allocated buffer */
|
|
||||||
Xml_node const _xml; /* referring to buffer of '_ptr' */
|
struct Allocation { char *ptr; size_t size; } const _allocation;
|
||||||
|
|
||||||
|
Xml_node const _xml { _allocation.ptr, _allocation.size };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \throw Allocator::Out_of_memory
|
* \throw Allocator::Out_of_memory
|
||||||
*/
|
*/
|
||||||
static char const *_init_ptr(Allocator &alloc, Xml_node node)
|
Allocation _copy_xml_node(Xml_node node)
|
||||||
{
|
{
|
||||||
char *ptr = nullptr;
|
Allocation allocation { };
|
||||||
|
|
||||||
node.with_raw_node([&] (char const *start, size_t length) {
|
node.with_raw_node([&] (char const *start, size_t length) {
|
||||||
ptr = (char *)alloc.alloc(length);
|
allocation = Allocation { (char *)_alloc.alloc(length), length };
|
||||||
Genode::memcpy(ptr, start, length);
|
Genode::memcpy(allocation.ptr, start, length);
|
||||||
});
|
});
|
||||||
|
|
||||||
return ptr;
|
return allocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate XML into allocated buffer
|
||||||
|
*
|
||||||
|
* \throw Allocation::Out_of_memory
|
||||||
|
*/
|
||||||
|
template <typename FN>
|
||||||
|
Allocation _generate(char const *node_name, FN const &fn, size_t size)
|
||||||
|
{
|
||||||
|
Allocation allocation { };
|
||||||
|
|
||||||
|
retry<Xml_generator::Buffer_exceeded>(
|
||||||
|
|
||||||
|
[&] () {
|
||||||
|
allocation = Allocation { (char *)_alloc.alloc(size), size };
|
||||||
|
Xml_generator xml(allocation.ptr, size, node_name,
|
||||||
|
[&] () { fn(xml); }); },
|
||||||
|
|
||||||
|
[&] () {
|
||||||
|
_alloc.free(allocation.ptr, allocation.size);
|
||||||
|
allocation = { };
|
||||||
|
size = size*2;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return allocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -53,18 +83,50 @@ class Genode::Buffered_xml
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor for buffering a copy of the specified XML node
|
||||||
*
|
*
|
||||||
* \throw Allocator::Out_of_memory
|
* \throw Allocator::Out_of_memory
|
||||||
*/
|
*/
|
||||||
Buffered_xml(Allocator &alloc, Xml_node node)
|
Buffered_xml(Allocator &alloc, Xml_node node)
|
||||||
:
|
:
|
||||||
_alloc(alloc), _ptr(_init_ptr(alloc, node)), _xml(_ptr, node.size())
|
_alloc(alloc), _allocation(_copy_xml_node(node))
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
~Buffered_xml() { _alloc.free(const_cast<char *>(_ptr), _xml.size()); }
|
struct Min_size { size_t value; };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for buffering generated XML
|
||||||
|
*
|
||||||
|
* \param name name of top-level XML node
|
||||||
|
* \param fn functor that takes an 'Xml_generator &' as argument
|
||||||
|
* \param size initial allocation size
|
||||||
|
*
|
||||||
|
* \throw Allocator::Out_of_memory
|
||||||
|
*/
|
||||||
|
template <typename FN>
|
||||||
|
Buffered_xml(Allocator &alloc, char const *name, FN const &fn, Min_size size)
|
||||||
|
:
|
||||||
|
_alloc(alloc), _allocation(_generate(name, fn, size.value))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
template <typename FN>
|
||||||
|
Buffered_xml(Allocator &alloc, char const *name, FN const &fn)
|
||||||
|
:
|
||||||
|
Buffered_xml(alloc, name, fn, Min_size{4000})
|
||||||
|
{ }
|
||||||
|
|
||||||
|
~Buffered_xml() { _alloc.free(_allocation.ptr, _allocation.size); }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* \deprecated Use 'with_xml_node' instead
|
||||||
|
*/
|
||||||
Xml_node xml() const { return _xml; }
|
Xml_node xml() const { return _xml; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call functor 'fn' with 'Xml_node const &' as argument
|
||||||
|
*/
|
||||||
|
template <typename FN>
|
||||||
|
void with_xml_node(FN const &fn) const { fn(_xml); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _OS__BUFFERED_XML_H_ */
|
#endif /* _OS__BUFFERED_XML_H_ */
|
||||||
|
|
Loading…
Reference in New Issue