diff --git a/repos/base/include/util/string.h b/repos/base/include/util/string.h index 2f549a4b99..3726005c26 100644 --- a/repos/base/include/util/string.h +++ b/repos/base/include/util/string.h @@ -23,6 +23,7 @@ namespace Genode { class Number_of_bytes; + class Byte_range_ptr; class Cstring; template class String; } @@ -67,6 +68,22 @@ class Genode::Number_of_bytes }; +/** + * Data structure for describing a byte buffer + * + * The type is intended to be used as 'Byte_range_ptr const &' argument. + * It is deliberately non-copyable. + */ +struct Genode::Byte_range_ptr +{ + char * const start; + size_t const num_bytes; + + Byte_range_ptr(char *start, size_t num_bytes) + : start(start), num_bytes(num_bytes) { } +}; + + /*********************** ** Utility functions ** ***********************/ diff --git a/repos/os/include/os/vfs.h b/repos/os/include/os/vfs.h index 8c9f23aee1..66cf242681 100644 --- a/repos/os/include/os/vfs.h +++ b/repos/os/include/os/vfs.h @@ -31,6 +31,12 @@ namespace Genode { class Watcher; template class Watch_handler; + template + void with_raw_file_content(Readonly_file const &, + Byte_range_ptr const &, FN const &); + template + void with_xml_file_content(Readonly_file const &, + Byte_range_ptr const &, FN const &); } @@ -487,6 +493,60 @@ class Genode::Readonly_file : public File }; +/** + * Call functor 'fn' with the data pointer and size in bytes + * + * If the buffer has a size of zero, 'fn' is not called. + */ +template +void Genode::with_raw_file_content(Readonly_file const &file, + Byte_range_ptr const &range, FN const &fn) +{ + if (range.num_bytes == 0) + return; + + size_t total_read = 0; + while (total_read < range.num_bytes) { + size_t read_bytes = file.read(Readonly_file::At{total_read}, + range.start + total_read, + range.num_bytes - total_read); + + if (read_bytes == 0) + break; + + total_read += read_bytes; + } + + if (total_read != range.num_bytes) + throw File::Truncated_during_read(); + + fn(range.start, range.num_bytes); +} + + +/** + * Call functor 'fn' with content as 'Xml_node' argument + * + * If the file does not contain valid XML, 'fn' is called with an + * '' node as argument. + */ +template +void Genode::with_xml_file_content(Readonly_file const &file, + Byte_range_ptr const &range, FN const &fn) +{ + with_raw_file_content(file, range, + [&] (char const *ptr, size_t num_bytes) { + try { + fn(Xml_node(ptr, num_bytes)); + return; + } + catch (Xml_node::Invalid_syntax) { } + + fn(Xml_node("")); + }); +} + + class Genode::File_content { private: @@ -533,22 +593,10 @@ class Genode::File_content : _buffer(alloc, min((size_t)dir.file_size(rel_path), limit.value)) { - Readonly_file file {dir, rel_path}; - - size_t total_read = 0; - while (total_read < _buffer.size) { - size_t read_bytes = file.read(Readonly_file::At{total_read}, - _buffer.ptr + total_read, - _buffer.size - total_read); - - if (read_bytes == 0) - break; - - total_read += read_bytes; - } - - if (total_read != _buffer.size) - throw Truncated_during_read(); + /* read the file content into the buffer */ + with_raw_file_content(Readonly_file(dir, rel_path), + Byte_range_ptr(_buffer.ptr, _buffer.size), + [] (char const*, size_t) { }); } /**