summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/treebuilder/internal.h3
-rw-r--r--src/treebuilder/treebuilder.c71
-rw-r--r--src/utils/Makefile2
-rw-r--r--src/utils/string.c62
-rw-r--r--src/utils/string.h16
5 files changed, 152 insertions, 2 deletions
diff --git a/src/treebuilder/internal.h b/src/treebuilder/internal.h
index ba69660..6a35632 100644
--- a/src/treebuilder/internal.h
+++ b/src/treebuilder/internal.h
@@ -155,6 +155,9 @@ bool formatting_list_replace(hubbub_treebuilder *treebuilder,
element_type type, void *node, uint32_t stack_index,
element_type *otype, void **onode, uint32_t *ostack_index);
+void adjust_foreign_attributes(hubbub_treebuilder *treebuilder,
+ hubbub_tag *tag);
+
#ifndef NDEBUG
#include <stdio.h>
diff --git a/src/treebuilder/treebuilder.c b/src/treebuilder/treebuilder.c
index 2ca2132..28621bd 100644
--- a/src/treebuilder/treebuilder.c
+++ b/src/treebuilder/treebuilder.c
@@ -12,7 +12,7 @@
#include "treebuilder/internal.h"
#include "treebuilder/treebuilder.h"
#include "utils/utils.h"
-
+#include "utils/string.h"
static const struct {
const char *name;
@@ -1242,6 +1242,75 @@ bool formatting_list_replace(hubbub_treebuilder *treebuilder,
return true;
}
+/**
+ * Adjust foreign attributes.
+ *
+ * \param treebuilder Treebuilder instance
+ * \param tag Tag to adjust the attributes of
+ */
+void adjust_foreign_attributes(hubbub_treebuilder *treebuilder,
+ hubbub_tag *tag)
+{
+ for (size_t i = 0; i < tag->n_attributes; i++) {
+ hubbub_attribute *attr = &tag->attributes[i];
+ const uint8_t *name = treebuilder->input_buffer +
+ attr->name.data.off;
+
+#define S(s) (uint8_t *) s, SLEN(s)
+
+ /* 10 == strlen("xlink:href") */
+ if (attr->name.len >= 10 &&
+ strncmp((char *) name, "xlink:",
+ SLEN("xlink:")) == 0) {
+ size_t len = attr->name.len - 6;
+ name += 6;
+
+ if (hubbub_string_match(name, len, S("actutate")) ||
+ hubbub_string_match(name, len,
+ S("arcrole")) ||
+ hubbub_string_match(name, len,
+ S("href")) ||
+ hubbub_string_match(name, len,
+ S("role")) ||
+ hubbub_string_match(name, len,
+ S("show")) ||
+ hubbub_string_match(name, len,
+ S("title")) ||
+ hubbub_string_match(name, len,
+ S("type"))) {
+ attr->ns = HUBBUB_NS_XLINK;
+ attr->name.data.off += 6;
+ attr->name.len -= 6;
+ }
+ /* 8 == strlen("xml:base") */
+ } else if (attr->name.len >= 8 &&
+ strncmp((char *) name, "xml:", SLEN("xml:")) == 0) {
+ size_t len = attr->name.len - 4;
+ name += 4;
+
+ if (hubbub_string_match(name, len, S("base")) ||
+ hubbub_string_match(name, len,
+ S("lang")) ||
+ hubbub_string_match(name, len,
+ S("space"))) {
+ attr->ns = HUBBUB_NS_XML;
+ attr->name.data.off += 4;
+ attr->name.len -= 4;
+ }
+ } else if (hubbub_string_match(name, attr->name.len,
+ S("xmlns")) ||
+ hubbub_string_match(name, attr->name.len,
+ S("xmlns:xlink"))) {
+ attr->ns = HUBBUB_NS_XMLNS;
+ attr->name.data.off += 6;
+ attr->name.len -= 6;
+ }
+
+#undef S
+ }
+}
+
+
#ifndef NDEBUG
static const char *element_type_to_name(element_type type);
diff --git a/src/utils/Makefile b/src/utils/Makefile
index c9cd076..1910dc0 100644
--- a/src/utils/Makefile
+++ b/src/utils/Makefile
@@ -32,7 +32,7 @@ dirstack_$(sp) := $(d)
d := $(DIR)
# Sources
-SRCS_$(d) := dict.c errors.c utf8.c utf16.c
+SRCS_$(d) := dict.c errors.c utf8.c utf16.c string.c
# Append to sources for component
SOURCES += $(addprefix $(d), $(SRCS_$(d)))
diff --git a/src/utils/string.c b/src/utils/string.c
new file mode 100644
index 0000000..ea588f7
--- /dev/null
+++ b/src/utils/string.c
@@ -0,0 +1,62 @@
+/*
+ * This file is part of Hubbub.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2008 Andrew Sidwell
+ */
+
+#include <stddef.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include "utils/string.h"
+
+
+/**
+ * Check if one string starts with another.
+ *
+ * \param a String to compare
+ * \param a_len Length of first string
+ * \param b String to compare
+ * \param b_len Length of second string
+ */
+bool hubbub_string_starts(const uint8_t *a, size_t a_len,
+ const uint8_t *b, size_t b_len)
+{
+ uint8_t z1, z2;
+
+ if (a_len < b_len)
+ return false;
+
+ for (const uint8_t *s1 = a, *s2 = b; b_len > 0; s1++, s2++, b_len--)
+ {
+ z1 = *s1;
+ z2 = *s2;
+ if (z1 != z2) return false;
+ if (!z1) return true;
+ }
+
+ return true;
+}
+
+/**
+ * Check that one string is exactly equal to another
+ *
+ * \param a String to compare
+ * \param a_len Length of first string
+ * \param b String to compare
+ * \param b_len Length of second string
+ */
+bool hubbub_string_match(const uint8_t *a, size_t a_len,
+ const uint8_t *b, size_t b_len)
+{
+ if (a_len != b_len)
+ return false;
+
+ for (const uint8_t *s1 = a, *s2 = b; b_len > 0; s1++, s2++, b_len--)
+ {
+ if (*s1 != *s2) return false;
+ }
+
+ return true;
+}
+
diff --git a/src/utils/string.h b/src/utils/string.h
new file mode 100644
index 0000000..d6bfe42
--- /dev/null
+++ b/src/utils/string.h
@@ -0,0 +1,16 @@
+/*
+ * This file is part of Hubbub.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2008 Andrew Sidwell
+ */
+
+#ifndef hubbub_string_h_
+#define hubbub_string_h_
+
+bool hubbub_string_starts(const uint8_t *a, size_t a_len,
+ const uint8_t *b, size_t b_len);
+bool hubbub_string_match(const uint8_t *a, size_t a_len,
+ const uint8_t *b, size_t b_len);
+
+#endif