parent
e590d90bf6
commit
6ecbc419c0
|
@ -87,6 +87,30 @@ class Genode::Xml_generator
|
||||||
*/
|
*/
|
||||||
void append(char const *src) { append(src, strlen(src)); }
|
void append(char const *src) { append(src, strlen(src)); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append character, sanitize it if needed
|
||||||
|
*/
|
||||||
|
void append_sanitized(char const c)
|
||||||
|
{
|
||||||
|
switch (c) {
|
||||||
|
case 0: append("�"); break;
|
||||||
|
case '>': append(">"); break;
|
||||||
|
case '<': append("<"); break;
|
||||||
|
case '&': append("&"); break;
|
||||||
|
case '"': append("""); break;
|
||||||
|
case '\'': append("'"); break;
|
||||||
|
default: append(c); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append character buffer, sanitize characters if needed
|
||||||
|
*/
|
||||||
|
void append_sanitized(char const *src, size_t len)
|
||||||
|
{
|
||||||
|
for (; len--; append_sanitized(*src++));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return unused part of the buffer
|
* Return unused part of the buffer
|
||||||
*/
|
*/
|
||||||
|
@ -192,7 +216,7 @@ class Genode::Xml_generator
|
||||||
dst.append(' ');
|
dst.append(' ');
|
||||||
dst.append(name);
|
dst.append(name);
|
||||||
dst.append("=\"");
|
dst.append("=\"");
|
||||||
dst.append(value);
|
dst.append(value, strlen(value));
|
||||||
dst.append("\"");
|
dst.append("\"");
|
||||||
|
|
||||||
_attr_offset += gap;
|
_attr_offset += gap;
|
||||||
|
@ -201,9 +225,14 @@ class Genode::Xml_generator
|
||||||
void append(char const *src, size_t src_len)
|
void append(char const *src, size_t src_len)
|
||||||
{
|
{
|
||||||
Out_buffer content_buffer = _content_buffer(false);
|
Out_buffer content_buffer = _content_buffer(false);
|
||||||
|
|
||||||
content_buffer.append(src, src_len);
|
content_buffer.append(src, src_len);
|
||||||
|
_commit_content(content_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void append_sanitized(char const *src, size_t src_len)
|
||||||
|
{
|
||||||
|
Out_buffer content_buffer = _content_buffer(false);
|
||||||
|
content_buffer.append_sanitized(src, src_len);
|
||||||
_commit_content(content_buffer);
|
_commit_content(content_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,6 +329,16 @@ class Genode::Xml_generator
|
||||||
_curr_node->append(str, str_len == ~0UL ? strlen(str) : str_len);
|
_curr_node->append(str, str_len == ~0UL ? strlen(str) : str_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append sanitized content to XML node
|
||||||
|
*
|
||||||
|
* This method must not be followed by calls of 'attribute'.
|
||||||
|
*/
|
||||||
|
void append_sanitized(char const *str, size_t str_len = ~0UL)
|
||||||
|
{
|
||||||
|
_curr_node->append_sanitized(str, str_len == ~0UL ? strlen(str) : str_len);
|
||||||
|
}
|
||||||
|
|
||||||
size_t used() const { return _out_buffer.used(); }
|
size_t used() const { return _out_buffer.used(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -396,6 +396,66 @@ class Genode::Xml_node
|
||||||
Token next_token() const { return _next; }
|
Token next_token() const { return _next; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class to decode XML character entities
|
||||||
|
*/
|
||||||
|
struct Decoded_character
|
||||||
|
{
|
||||||
|
char character = 0;
|
||||||
|
size_t encoded_len = 1;
|
||||||
|
|
||||||
|
struct Translation
|
||||||
|
{
|
||||||
|
char character;
|
||||||
|
char const *seq;
|
||||||
|
size_t seq_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
static Translation translate(char const *src, size_t src_len)
|
||||||
|
{
|
||||||
|
enum { NUM = 6 };
|
||||||
|
static Translation translations[NUM] = {
|
||||||
|
{ '>', ">", 4 },
|
||||||
|
{ '<', "<", 4 },
|
||||||
|
{ '&', "&", 5 },
|
||||||
|
{ '"', """, 6 },
|
||||||
|
{ '\'', "'", 6 },
|
||||||
|
{ 0, "�", 6 }
|
||||||
|
};
|
||||||
|
|
||||||
|
if (src_len == 0)
|
||||||
|
return { 0, nullptr, 0 };
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < NUM; i++) {
|
||||||
|
|
||||||
|
Translation const &translation = translations[i];
|
||||||
|
|
||||||
|
if (src_len < translation.seq_len
|
||||||
|
|| memcmp(src, translation.seq, translation.seq_len))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* translation matches */
|
||||||
|
return translation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sequence is not known, pass single character as is */
|
||||||
|
return { *src, nullptr, 1 };
|
||||||
|
}
|
||||||
|
|
||||||
|
Decoded_character(char const *src, size_t src_len)
|
||||||
|
{
|
||||||
|
if (*src != '&' || src_len == 0) {
|
||||||
|
character = *src;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Translation const translation = translate(src, src_len);
|
||||||
|
|
||||||
|
character = translation.character;
|
||||||
|
encoded_len = translation.seq_len;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const char *_addr; /* first character of XML data */
|
const char *_addr; /* first character of XML data */
|
||||||
size_t _max_len; /* length of XML data in characters */
|
size_t _max_len; /* length of XML data in characters */
|
||||||
int _num_sub_nodes; /* number of immediate sub nodes */
|
int _num_sub_nodes; /* number of immediate sub nodes */
|
||||||
|
@ -605,6 +665,47 @@ class Genode::Xml_node
|
||||||
return _end_tag.token().start() - content_addr();
|
return _end_tag.token().start() - content_addr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export decoded node content from XML node
|
||||||
|
*
|
||||||
|
* \param dst destination buffer
|
||||||
|
* \param dst_len size of destination buffer in bytes
|
||||||
|
* \return number of bytes written to the destination buffer
|
||||||
|
*
|
||||||
|
* This function transforms XML character entities into their
|
||||||
|
* respective characters.
|
||||||
|
*/
|
||||||
|
size_t decoded_content(char *dst, size_t dst_len) const
|
||||||
|
{
|
||||||
|
size_t result_len = 0;
|
||||||
|
char const *src = content_base();
|
||||||
|
size_t src_len = content_size();
|
||||||
|
|
||||||
|
for (; dst_len > 1 && src_len; result_len++) {
|
||||||
|
|
||||||
|
Decoded_character const decoded_character(src, src_len);
|
||||||
|
|
||||||
|
*dst++ = decoded_character.character;
|
||||||
|
|
||||||
|
src += decoded_character.encoded_len;
|
||||||
|
src_len -= decoded_character.encoded_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read decoded node content as Genode::String
|
||||||
|
*/
|
||||||
|
template <typename STRING>
|
||||||
|
STRING decoded_content() const
|
||||||
|
{
|
||||||
|
char buf[STRING::capacity() + 1];
|
||||||
|
size_t const len = decoded_content(buf, sizeof(buf));
|
||||||
|
buf[min(len, STRING::capacity())] = 0;
|
||||||
|
return STRING(buf);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the number of the XML node's immediate sub nodes
|
* Return the number of the XML node's immediate sub nodes
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#include <base/printf.h>
|
#include <base/printf.h>
|
||||||
#include <util/xml_generator.h>
|
#include <util/xml_generator.h>
|
||||||
|
#include <util/xml_node.h>
|
||||||
|
|
||||||
using Genode::size_t;
|
using Genode::size_t;
|
||||||
|
|
||||||
|
@ -68,6 +69,37 @@ int main(int argc, char **argv)
|
||||||
catch (Genode::Xml_generator::Buffer_exceeded) {
|
catch (Genode::Xml_generator::Buffer_exceeded) {
|
||||||
printf("buffer exceeded (expected error)\n"); }
|
printf("buffer exceeded (expected error)\n"); }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test the sanitizing of XML node content
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
/* generate pattern that contains all possible byte values */
|
||||||
|
char pattern[256];
|
||||||
|
for (unsigned i = 0; i < sizeof(pattern); i++)
|
||||||
|
pattern[i] = i;
|
||||||
|
|
||||||
|
/* generate XML with the pattern as content */
|
||||||
|
Genode::Xml_generator xml(dst, sizeof(dst), "data", [&] () {
|
||||||
|
xml.append_sanitized(pattern, sizeof(pattern)); });
|
||||||
|
|
||||||
|
/* parse the generated XML data */
|
||||||
|
Genode::Xml_node node(dst);
|
||||||
|
|
||||||
|
/* obtain decoded node content */
|
||||||
|
char decoded[sizeof(dst)];
|
||||||
|
size_t const decoded_len = node.decoded_content(decoded, sizeof(decoded));
|
||||||
|
|
||||||
|
/* compare result with original pattern */
|
||||||
|
if (decoded_len != sizeof(pattern)) {
|
||||||
|
printf("decoded content has unexpected length %zd\n", decoded_len);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (Genode::memcmp(decoded, pattern, sizeof(pattern))) {
|
||||||
|
printf("decoded content does not match original pattern\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
printf("--- XML generator test finished ---\n");
|
printf("--- XML generator test finished ---\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user