summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--wocky/wocky-node.c112
1 files changed, 102 insertions, 10 deletions
diff --git a/wocky/wocky-node.c b/wocky/wocky-node.c
index f676cf5..f6f50fe 100644
--- a/wocky/wocky-node.c
+++ b/wocky/wocky-node.c
@@ -63,6 +63,98 @@ static NSPrefix default_attr_ns_prefixes[] =
static GHashTable *user_ns_prefixes = NULL;
static GHashTable *default_ns_prefixes = NULL;
+/* Do a strndup operation, but at the same time replace all characters that
+ * aren't valid according to g_utf8_validate by � */
+
+static gchar *
+strndup_make_valid (const gchar *str, gssize len)
+{
+ const gchar *remainder = str;
+ GString *result;
+ const gchar *endp;
+ gssize left = len;
+
+ /* Simplify things by always keeping track of the string lenght */
+ if (left < 0)
+ left = strlen (remainder);
+
+ result = g_string_sized_new (len);
+
+ while (!g_utf8_validate (remainder, left, &endp))
+ {
+ g_string_append_len (result, remainder, endp - remainder);
+ /* append U+FFFD REPLACEMENT CHARACTER */
+ g_string_append (result, "\357\277\275");
+
+ /* left, minus the valid part of the string */
+ left -= (endp - remainder);
+
+ remainder = g_utf8_find_next_char (endp, endp + left);
+ /* left, minus the skipped part, if there is no next utf8 character,
+ * nothing is left */
+ if (remainder == NULL)
+ left = 0;
+ else if (left > 0)
+ left -= (remainder - endp);
+ }
+ g_string_append_len (result, remainder, left);
+
+ return g_string_free (result, FALSE);
+}
+
+static gchar *
+strndup_validated (const gchar *str, gssize len)
+{
+ if (str == NULL)
+ return NULL;
+
+ /* Fast path, string happily validates, simple copy */
+ if (G_LIKELY (g_utf8_validate (str, len, NULL)))
+ {
+ if (len < 0)
+ return g_strdup (str);
+ else
+ return g_strndup (str, len);
+ }
+
+ /* slow path, string doesn't validate.. */
+ return strndup_make_valid (str, len);
+}
+
+static gchar *
+concat_validated (const gchar *s1, const gchar *s2, gssize s2_size)
+{
+ gchar *result;
+ gssize s1_size;
+ /* data to be freed after use if needed */
+ const gchar *to_free = NULL;
+
+ /* concatting to nothing, iotw, strndup :) */
+ if (s1 == NULL)
+ return strndup_validated (s2, s2_size);
+
+ s1_size = strlen (s1);
+ if (s2_size < 0)
+ s2_size = strlen (s2);
+
+ if (G_UNLIKELY (!g_utf8_validate (s2, s2_size, NULL)))
+ {
+ /* Make a validated copy we will free later on. Making a copy to just
+ * concat and then free isn't the most efficient way, but at this point
+ * we're out of the fast-path anyway */
+ to_free = s2 = strndup_make_valid (s2, s2_size);
+ s2_size = strlen (s2);
+ }
+
+ result = g_malloc0 (s1_size + s2_size + 1);
+ memcpy (result, s1, s1_size);
+ memcpy (result + s1_size, s2, s2_size);
+ g_free ((gchar *) to_free);
+
+ return result;
+}
+
+
static WockyNode *
new_node (const char *name, GQuark ns)
{
@@ -73,7 +165,7 @@ new_node (const char *name, GQuark ns)
result = g_slice_new0 (WockyNode);
- result->name = g_strdup (name);
+ result->name = strndup_validated (name, -1);
result->ns = ns;
return result;
@@ -322,7 +414,7 @@ ns_prefix_new (const gchar *urn,
{
NSPrefix *nsp = g_slice_new0 (NSPrefix);
nsp->ns_urn = urn;
- nsp->prefix = g_strdup (prefix);
+ nsp->prefix = strndup_validated (prefix, -1);
nsp->ns = ns;
return nsp;
@@ -514,8 +606,8 @@ wocky_node_set_attribute_n_ns (WockyNode *node, const gchar *key,
GSList *link;
Tuple search;
- a->key = g_strdup (key);
- a->value = g_strndup (value, value_size);
+ a->key = strndup_validated (key, -1);
+ a->value = strndup_validated (value, value_size);
a->prefix = g_strdup (wocky_node_attribute_ns_get_prefix_from_urn (ns));
a->ns = (ns != NULL) ? g_quark_from_string (ns) : 0;
@@ -863,7 +955,7 @@ wocky_node_set_language_n (WockyNode *node, const gchar *lang,
gsize lang_size)
{
g_free (node->language);
- node->language = g_strndup (lang, lang_size);
+ node->language = strndup_validated (lang, lang_size);
}
/**
@@ -894,7 +986,7 @@ void
wocky_node_set_content (WockyNode *node, const gchar *content)
{
g_free (node->content);
- node->content = g_strdup (content);
+ node->content = strndup_validated (content, -1);
}
/**
@@ -909,7 +1001,7 @@ wocky_node_append_content (WockyNode *node,
const gchar *content)
{
gchar *t = node->content;
- node->content = g_strconcat (t, content, NULL);
+ node->content = concat_validated (t, content, -1);
g_free (t);
}
@@ -926,9 +1018,9 @@ void
wocky_node_append_content_n (WockyNode *node, const gchar *content,
gsize size)
{
- gsize csize = node->content != NULL ? strlen (node->content) : 0;
- node->content = g_realloc (node->content, csize + size + 1);
- g_strlcpy (node->content + csize, content, size + 1);
+ gchar *t = node->content;
+ node->content = concat_validated (t, content, size);
+ g_free (t);
}
static gboolean