Refactor XBEL writing to use GString and filter out control characters

The writing becomes faster because we avoid some redundant allocations
and we improve XML compatibility by filtering out control characters
which are not supported in Midori.
This commit is contained in:
Christian Dywan 2009-12-03 23:13:15 +01:00
parent 36a5ef50b7
commit da0304964e

View file

@ -454,74 +454,114 @@ midori_array_from_file (KatzeArray* array,
} }
#endif #endif
static gchar* /* Inspired by append_escaped_text() from gmarkup.c in Glib.
_simple_xml_element (const gchar* name, The main difference is that we filter out control characters. */
const gchar* value) static void
string_append_escaped (GString *str,
const gchar *text)
{ {
gchar* value_escaped; gssize length;
gchar* markup; const gchar* p;
const gchar* end;
gunichar c;
if (!value) length = strlen (text);
return g_strdup (""); p = text;
value_escaped = g_markup_escape_text (value, -1); end = text + length;
markup = g_strdup_printf ("<%s>%s</%s>\n", name, value_escaped, name);
g_free (value_escaped); while (p != end)
return markup; {
const gchar *next;
next = g_utf8_next_char (p);
switch (*p)
{
case '&':
g_string_append (str, "&amp;");
break;
case '<':
g_string_append (str, "&lt;");
break;
case '>':
g_string_append (str, "&gt;");
break;
case '\'':
g_string_append (str, "&apos;");
break;
case '"':
g_string_append (str, "&quot;");
break;
default:
c = g_utf8_get_char (p);
if (g_unichar_iscntrl (c))
g_string_append_c (str, ' ');
else if ((0x1 <= c && c <= 0x8)
|| (0xb <= c && c <= 0xc)
|| (0xe <= c && c <= 0x1f)
|| (0x7f <= c && c <= 0x84)
|| (0x86 <= c && c <= 0x9f))
g_string_append_printf (str, "&#x%x;", c);
else
g_string_append_len (str, p, next - p);
break;
}
p = next;
}
} }
static gchar* static void
katze_item_to_data (KatzeItem* item) string_append_xml_element (GString* string,
const gchar* name,
const gchar* value)
{
if (value)
{
g_string_append_printf (string, "<%s>", name);
string_append_escaped (string, value);
g_string_append_printf (string, "</%s>\n", name);
}
}
static void
string_append_item (GString* string,
KatzeItem* item)
{ {
gchar* markup; gchar* markup;
gchar* metadata; gchar* metadata;
g_return_val_if_fail (KATZE_IS_ITEM (item), NULL); g_return_if_fail (KATZE_IS_ITEM (item));
markup = NULL; markup = NULL;
metadata = katze_item_metadata_to_xbel (item); metadata = katze_item_metadata_to_xbel (item);
if (KATZE_IS_ARRAY (item)) if (KATZE_IS_ARRAY (item))
{ {
GString* _markup = g_string_new (NULL);
guint i = 0; guint i = 0;
KatzeItem* _item; KatzeItem* _item;
while ((_item = katze_array_get_nth_item (KATZE_ARRAY (item), i++))) KatzeArray* array = KATZE_ARRAY (item);
{
gchar* item_markup = katze_item_to_data (_item); g_string_append (string, "<folder>\n");
g_string_append (_markup, item_markup); /* FIXME: " folded=\"no\" */
g_free (item_markup); string_append_xml_element (string, "title", katze_item_get_name (item));
} string_append_xml_element (string, "desc", katze_item_get_text (item));
/* gchar* folded = item->folded ? NULL : g_strdup_printf (" folded=\"no\""); */ while ((_item = katze_array_get_nth_item (array, i++)))
gchar* title = _simple_xml_element ("title", katze_item_get_name (item)); string_append_item (string, _item);
gchar* desc = _simple_xml_element ("desc", katze_item_get_text (item)); g_string_append (string, metadata);
markup = g_strdup_printf ("<folder%s>\n%s%s%s%s</folder>\n", g_string_append (string, "</folder>\n");
"" /* folded ? folded : "" */,
title, desc,
_markup->str,
metadata);
g_string_free (_markup, TRUE);
/* g_free (folded); */
g_free (title);
g_free (desc);
} }
else if (katze_item_get_uri (item)) else if (katze_item_get_uri (item))
{ {
gchar* href_escaped = g_markup_escape_text (katze_item_get_uri (item), -1); g_string_append (string, "<bookmark href=\"");
gchar* href = g_strdup_printf (" href=\"%s\"", href_escaped); string_append_escaped (string, katze_item_get_uri (item));
g_free (href_escaped); g_string_append (string, "\">\n");
gchar* title = _simple_xml_element ("title", katze_item_get_name (item)); string_append_xml_element (string, "title", katze_item_get_name (item));
gchar* desc = _simple_xml_element ("desc", katze_item_get_text (item)); string_append_xml_element (string, "desc", katze_item_get_text (item));
markup = g_strdup_printf ("<bookmark%s>\n%s%s%s</bookmark>\n", g_string_append (string, metadata);
href, g_string_append (string, "</bookmark>\n");
title, desc,
metadata);
g_free (href);
g_free (title);
g_free (desc);
} }
else else
markup = g_strdup ("<separator/>\n"); g_string_append (string, "<separator/>\n");
g_free (metadata); g_free (metadata);
return markup;
} }
static gchar* static gchar*
@ -547,18 +587,26 @@ katze_item_metadata_to_xbel (KatzeItem* item)
while ((key = g_list_nth_data (keys, i++))) while ((key = g_list_nth_data (keys, i++)))
if ((value = katze_item_get_meta_string (item, key))) if ((value = katze_item_get_meta_string (item, key)))
{ {
gchar* escaped = g_markup_escape_text (value, -1);
namespace = strchr (key, ':'); namespace = strchr (key, ':');
if (key[0] == ':') /* MicroB uses un-namespaced children */ if (key[0] == ':') /* MicroB uses un-namespaced children */
{ {
key = &key[1]; key = &key[1];
g_string_append_printf (markdown, "<%s>%s</%s>\n", key, escaped, key); g_string_append_printf (markdown, "<%s>", key);
string_append_escaped (markdown, value);
g_string_append_printf (markdown, "</%s>\n", key);
} }
else if (namespace) else if (namespace)
g_string_append_printf (markup, " %s=\"%s\"", key, escaped); {
g_string_append_printf (markup, " %s=\"", key);
string_append_escaped (markup, value);
g_string_append_c (markup, '\"');
}
else else
g_string_append_printf (markup, " midori:%s=\"%s\"", key, escaped); {
g_free (escaped); g_string_append_printf (markup, " midori:%s=\"", key);
string_append_escaped (markup, value);
g_string_append_c (markup, '\"');
}
} }
if (!namespace) if (!namespace)
{ {
@ -577,46 +625,29 @@ static gchar*
katze_array_to_xbel (KatzeArray* array, katze_array_to_xbel (KatzeArray* array,
GError** error) GError** error)
{ {
GString* inner_markup; gchar* metadata = katze_item_metadata_to_xbel (KATZE_ITEM (array));
guint i; guint i;
KatzeItem* item; KatzeItem* item;
gchar* item_xml;
const gchar* namespacing;
gchar* title;
gchar* desc;
gchar* metadata;
gchar* outer_markup;
inner_markup = g_string_new (NULL); GString* markup = g_string_new (
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<!DOCTYPE xbel PUBLIC \"+//IDN python.org//DTD "
"XML Bookmark Exchange Language 1.0//EN//XML\" "
"\"http://www.python.org/topics/xml/dtds/xbel-1.0.dtd\">\n"
"<xbel version=\"1.0\""
" xmlns:midori=\"http://www.twotoasts.de\""
">\n");
string_append_xml_element (markup, "title", katze_item_get_name (KATZE_ITEM (array)));
string_append_xml_element (markup, "desc", katze_item_get_text (KATZE_ITEM (array)));
g_string_append (markup, metadata);
i = 0; i = 0;
while ((item = katze_array_get_nth_item (array, i++))) while ((item = katze_array_get_nth_item (array, i++)))
{ string_append_item (markup, item);
item_xml = katze_item_to_data (item); g_string_append (markup, "</xbel>\n");
g_string_append (inner_markup, item_xml);
g_free (item_xml);
}
namespacing = " xmlns:midori=\"http://www.twotoasts.de\"";
title = _simple_xml_element ("title", katze_item_get_name (KATZE_ITEM (array)));
desc = _simple_xml_element ("desc", katze_item_get_text (KATZE_ITEM (array)));
metadata = katze_item_metadata_to_xbel (KATZE_ITEM (array));
outer_markup = g_strdup_printf (
"%s%s<xbel version=\"1.0\"%s>\n%s%s%s%s</xbel>\n",
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
"<!DOCTYPE xbel PUBLIC \"+//IDN python.org//DTD "
"XML Bookmark Exchange Language 1.0//EN//XML\" "
"\"http://www.python.org/topics/xml/dtds/xbel-1.0.dtd\">\n",
namespacing,
title,
desc,
metadata,
inner_markup->str);
g_string_free (inner_markup, TRUE);
g_free (title);
g_free (desc);
g_free (metadata); g_free (metadata);
return outer_markup; return g_string_free (markup, FALSE);
} }
static gboolean static gboolean