summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn Mark Bell <jmb@netsurf-browser.org>2007-09-29 01:01:55 +0000
committerJohn Mark Bell <jmb@netsurf-browser.org>2007-09-29 01:01:55 +0000
commit6b1aeb6465f339bfbc7be33b1ecab3f235adbe7f (patch)
tree720ad0f18306af6b11b9b1c0dbd622bf57792af6 /src
parent83bc8f09261fb4d265cc79d39e740b4a0c9648e2 (diff)
downloadlibdom-6b1aeb6465f339bfbc7be33b1ecab3f235adbe7f.tar.gz
libdom-6b1aeb6465f339bfbc7be33b1ecab3f235adbe7f.tar.bz2
Introduce global initialistaion/finalisation for DOM library. This should be used to initialise any parts of the library before they are used. Mostly, this will comprise of static initialisers. Finalisation cleans up afterwards. This API is only exposed to language-specific binding libraries -- they should expose their own global initialisation/finalisation routines which call the core libdom ones.
Introduce new utility code for namespace and qname processing. Port dom_document_create_element_ns() and dom_document_create_attribute_ns() to this new code. Make libdom-libxml's initialiser initialise libdom itself first of all. svn path=/trunk/dom/; revision=3604
Diffstat (limited to 'src')
-rw-r--r--src/Makefile3
-rw-r--r--src/bootstrap/Makefile2
-rw-r--r--src/bootstrap/init_fini.c47
-rw-r--r--src/core/document.c87
-rw-r--r--src/utils/Makefile53
-rw-r--r--src/utils/namespace.c218
-rw-r--r--src/utils/namespace.h33
-rw-r--r--src/utils/utils.h4
8 files changed, 372 insertions, 75 deletions
diff --git a/src/Makefile b/src/Makefile
index b0f78b2..6c780a4 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -36,16 +36,19 @@ OBJS =
release: $(addprefix Release/, $(addsuffix .o, $(OBJS)))
@${MAKE} -C bootstrap release
@${MAKE} -C core release
+ @${MAKE} -C utils release
@${AR} ${ARFLAGS} $(RELEASE) Release/*
debug: $(addprefix Debug/, $(addsuffix .o, $(OBJS)))
@${MAKE} -C bootstrap debug
@${MAKE} -C core debug
+ @${MAKE} -C utils debug
@${AR} ${ARFLAGS} $(DEBUG) Debug/*
clean:
@${MAKE} -C bootstrap clean
@${MAKE} -C core clean
+ @${MAKE} -C utils clean
ifneq (${OBJS}, )
-@${RM} ${RMFLAGS} $(addprefix Release/, $(addsuffix .o, ${OBJS}))
-@${RM} ${RMFLAGS} $(addprefix Debug/, $(addsuffix .o, ${OBJS}))
diff --git a/src/bootstrap/Makefile b/src/bootstrap/Makefile
index 6c904cc..0eed6c7 100644
--- a/src/bootstrap/Makefile
+++ b/src/bootstrap/Makefile
@@ -22,7 +22,7 @@
CFLAGS += -I$(CURDIR)
# Objects
-OBJS = implregistry
+OBJS = implregistry init_fini
.PHONY: clean debug distclean export release setup test
diff --git a/src/bootstrap/init_fini.c b/src/bootstrap/init_fini.c
new file mode 100644
index 0000000..001eaf9
--- /dev/null
+++ b/src/bootstrap/init_fini.c
@@ -0,0 +1,47 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
+ */
+
+#include <dom/bootstrap/implpriv.h>
+
+#include "utils/namespace.h"
+
+/**
+ * Initialise the dom library
+ *
+ * \param alloc Pointer to memory (de)allocation function
+ * \param pw Pointer to client-specific private data
+ * \return DOM_NO_ERR on success.
+ *
+ * This should be invoked by the binding's initialiser and must be
+ * the first DOM library method called.
+ */
+dom_exception dom_initialise(dom_alloc alloc, void *pw)
+{
+ dom_exception err;
+
+ err = _dom_namespace_initialise(alloc, pw);
+
+ return err;
+}
+
+/**
+ * Finalise the dom library
+ *
+ * \return DOM_NO_ERR on success.
+ *
+ * This should be invoked by the binding's finaliser and must be
+ * the last DOM library method called.
+ */
+dom_exception dom_finalise(void)
+{
+ dom_exception err;
+
+ err = _dom_namespace_finalise();
+
+ return err;
+}
+
diff --git a/src/core/document.c b/src/core/document.c
index b456983..5148224 100644
--- a/src/core/document.c
+++ b/src/core/document.c
@@ -25,6 +25,7 @@
#include "core/nodelist.h"
#include "core/pi.h"
#include "core/text.h"
+#include "utils/namespace.h"
#include "utils/utils.h"
struct dom_document_type;
@@ -551,52 +552,23 @@ dom_exception dom_document_create_element_ns(struct dom_document *doc,
struct dom_string *namespace, struct dom_string *qname,
struct dom_element **result)
{
- const uint8_t *qd, *c, *ln;
- size_t qlen;
- size_t local_len;
- size_t prefix_len;
- struct dom_string *prefix = NULL;
- struct dom_string *localname;
+ struct dom_string *prefix, *localname;
dom_exception err;
/** \todo ensure document supports XML feature */
- /** \todo validate qname */
- dom_string_get_data(qname, &qd, &qlen);
-
- /* Divide QName into prefix/localname pair */
- for (c = qd; c != qd + qlen; c++) {
- if (*c == (const uint8_t) ':')
- break;
- }
-
- if (c == qd + qlen) {
- ln = qd;
- local_len = qlen;
- prefix_len = 0;
- } else {
- ln = ++c;
- local_len = qlen - (c - qd);
- prefix_len = (c - qd - 1 /* ':' */);
- }
-
- if (prefix_len > 0) {
- err = dom_string_create_from_ptr(doc, qd, prefix_len, &prefix);
- if (err != DOM_NO_ERR) {
- return err;
- }
+ /* Validate qname */
+ err = _dom_namespace_validate_qname(qname, namespace);
+ if (err != DOM_NO_ERR) {
+ return err;
}
- err = dom_string_create_from_ptr(doc, ln, local_len, &localname);
+ /* Divide QName into prefix/localname pair */
+ err = _dom_namespace_split_qname(qname, doc, &prefix, &localname);
if (err != DOM_NO_ERR) {
- if (prefix != NULL) {
- dom_string_unref(prefix);
- }
return err;
}
- /** \todo validate namespace */
-
/* Attempt to create element */
err = dom_element_create(doc, localname, namespace, prefix, result);
@@ -641,52 +613,23 @@ dom_exception dom_document_create_attribute_ns(struct dom_document *doc,
struct dom_string *namespace, struct dom_string *qname,
struct dom_attr **result)
{
- const uint8_t *qd, *c, *ln;
- size_t qlen;
- size_t local_len;
- size_t prefix_len;
- struct dom_string *prefix = NULL;
- struct dom_string *localname;
+ struct dom_string *prefix, *localname;
dom_exception err;
/** \todo ensure document supports XML feature */
- /** \todo validate qname */
- dom_string_get_data(qname, &qd, &qlen);
-
- /* Divide QName into prefix/localname pair */
- for (c = qd; c != qd + qlen; c++) {
- if (*c == (const uint8_t) ':')
- break;
- }
-
- if (c == qd + qlen) {
- ln = qd;
- local_len = qlen;
- prefix_len = 0;
- } else {
- ln = ++c;
- local_len = qlen - (c - qd);
- prefix_len = (c - qd - 1 /* ':' */);
- }
-
- if (prefix_len > 0) {
- err = dom_string_create_from_ptr(doc, qd, prefix_len, &prefix);
- if (err != DOM_NO_ERR) {
- return err;
- }
+ /* Validate qname */
+ err = _dom_namespace_validate_qname(qname, namespace);
+ if (err != DOM_NO_ERR) {
+ return err;
}
- err = dom_string_create_from_ptr(doc, ln, local_len, &localname);
+ /* Divide QName into prefix/localname pair */
+ err = _dom_namespace_split_qname(qname, doc, &prefix, &localname);
if (err != DOM_NO_ERR) {
- if (prefix != NULL) {
- dom_string_unref(prefix);
- }
return err;
}
- /** \todo validate namespace */
-
/* Attempt to create attribute */
err = dom_attr_create(doc, localname, namespace, prefix, result);
diff --git a/src/utils/Makefile b/src/utils/Makefile
new file mode 100644
index 0000000..29369ae
--- /dev/null
+++ b/src/utils/Makefile
@@ -0,0 +1,53 @@
+# Makefile for libdom
+#
+# Toolchain is exported by top-level makefile
+#
+# Top-level makefile also exports the following variables:
+#
+# COMPONENT Name of component
+# EXPORT Absolute path of export directory
+# TOP Absolute path of source tree root
+#
+# The top-level makefile requires the following targets to exist:
+#
+# clean Clean source tree
+# debug Create a debug binary
+# distclean Fully clean source tree, back to pristine condition
+# export Export distributable components to ${EXPORT}
+# release Create a release binary
+# setup Perform any setup required prior to compilation
+# test Execute any test cases
+
+# Manipulate include paths
+CFLAGS += -I$(CURDIR)
+
+# Objects
+OBJS = namespace
+
+.PHONY: clean debug distclean export release setup test
+
+# Targets
+release: $(addprefix ../Release/, $(addsuffix .o, $(OBJS)))
+
+debug: $(addprefix ../Debug/, $(addsuffix .o, $(OBJS)))
+
+clean:
+ -@${RM} ${RMFLAGS} $(addprefix ../Release/, $(addsuffix .o, ${OBJS}))
+ -@${RM} ${RMFLAGS} $(addprefix ../Debug/, $(addsuffix .o, ${OBJS}))
+
+distclean:
+
+setup:
+
+export:
+
+test:
+
+# Pattern rules
+../Release/%.o: %.c
+ @${ECHO} ${ECHOFLAGS} "==> $<"
+ @${CC} -c ${CFLAGS} -DNDEBUG -o $@ $<
+
+../Debug/%.o: %.c
+ @${ECHO} ${ECHOFLAGS} "==> $<"
+ @${CC} -c -g ${CFLAGS} -o $@ $<
diff --git a/src/utils/namespace.c b/src/utils/namespace.c
new file mode 100644
index 0000000..25b56ee
--- /dev/null
+++ b/src/utils/namespace.c
@@ -0,0 +1,218 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
+ */
+
+#include <string.h>
+
+#include <dom/core/string.h>
+
+#include "utils/namespace.h"
+#include "utils/utils.h"
+
+/** XML namespace URI */
+static struct dom_string *xml;
+/** XMLNS namespace URI */
+static struct dom_string *xmlns;
+
+/**
+ * Initialise the namespace component
+ *
+ * \param alloc Pointer to memory (de)allocation function
+ * \param pw Pointer to client-specific private data
+ * \return DOM_NO_ERR on success.
+ */
+dom_exception _dom_namespace_initialise(dom_alloc alloc, void *pw)
+{
+ dom_exception err;
+
+ err = dom_string_create_from_ptr_no_doc(alloc, pw,
+ (const uint8_t *) "http://www.w3.org/XML/1998/namespace",
+ SLEN("http://www.w3.org/XML/1998/namespace"),
+ &xml);
+ if (err != DOM_NO_ERR) {
+ return err;
+ }
+
+ err = dom_string_create_from_ptr_no_doc(alloc, pw,
+ (const uint8_t *) "http://www.w3.org/2000/xmlns",
+ SLEN("http://www.w3.org/2000/xmlns"),
+ &xmlns);
+ if (err != DOM_NO_ERR) {
+ dom_string_unref(xml);
+ return err;
+ }
+
+ return DOM_NO_ERR;
+}
+
+/**
+ * Finalise the namespace component
+ *
+ * \return DOM_NO_ERR on success.
+ */
+dom_exception _dom_namespace_finalise(void)
+{
+ dom_string_unref(xmlns);
+ dom_string_unref(xml);
+
+ return DOM_NO_ERR;
+}
+
+/**
+ * Ensure a QName is valid
+ *
+ * \param qname The qname to validate
+ * \param namespace The namespace URI associated with the QName, or NULL
+ * \return DOM_NO_ERR if valid,
+ * DOM_INVALID_CHARACTER_ERR if ::qname contains an invalid character,
+ * DOM_NAMESPACE_ERR if ::qname is malformed, or it has a
+ * prefix and ::namespace is NULL, or
+ * ::qname has a prefix "xml" and
+ * ::namespace is not
+ * "http://www.w3.org/XML/1998/namespace",
+ * or ::qname has a prefix "xmlns" and
+ * ::namespace is not
+ * "http://www.w3.org/2000/xmlns", or
+ * ::namespace is
+ * "http://www.w3.org/2000/xmlns" and
+ * ::qname is not (or is not prefixed by)
+ * "xmlns".
+ */
+dom_exception _dom_namespace_validate_qname(struct dom_string *qname,
+ struct dom_string *namespace)
+{
+ const uint8_t *qname_data, *c;
+ size_t qname_len;
+
+ dom_string_get_data(qname, &qname_data, &qname_len);
+
+ /** \todo search qname for invalid characters */
+ /** \todo ensure qname is not malformed */
+
+ /* Find colon */
+ /** \todo assumes ASCII-compatible encoding */
+ for (c = qname_data; c != qname_data + qname_len; c++) {
+ if (*c == (const uint8_t) ':') {
+ break;
+ }
+ }
+
+ if (c == qname_data + qname_len) {
+ /* No prefix */
+ /* If namespace URI is for xmlns, ensure qname == "xmlns" */
+ if (namespace != NULL &&
+ dom_string_cmp(namespace, xmlns) == 0 &&
+ (qname_len != SLEN("xmlns") ||
+ strncmp((const char *) qname_data, "xmlns",
+ SLEN("xmlns")) != 0)) {
+ return DOM_NAMESPACE_ERR;
+ }
+ } else {
+ /* Prefix */
+ /* Ensure there is a namespace URI */
+ if (namespace == NULL) {
+ return DOM_NAMESPACE_ERR;
+ }
+
+ /* Test for invalid XML namespace */
+ if (c - qname_data == SLEN("xml") &&
+ strncmp((const char *) qname_data, "xml",
+ SLEN("xml")) == 0 &&
+ dom_string_cmp(namespace, xml) != 0) {
+ return DOM_NAMESPACE_ERR;
+ }
+
+ /* Test for invalid xmlns namespace */
+ if (c - qname_data == SLEN("xmlns") &&
+ strncmp((const char *) qname_data, "xmlns",
+ SLEN("xmlns")) == 0 &&
+ dom_string_cmp(namespace, xmlns) != 0) {
+ return DOM_NAMESPACE_ERR;
+ }
+
+ /* Test for presence of xmlns namespace with non xmlns prefix */
+ if (dom_string_cmp(namespace, xmlns) == 0 &&
+ (c - qname_data != SLEN("xmlns") ||
+ strncmp((const char *) qname_data, "xmlns",
+ SLEN("xmlns")) != 0)) {
+ return DOM_NAMESPACE_ERR;
+ }
+ }
+
+ return DOM_NO_ERR;
+}
+
+/**
+ * Split a QName into a namespace prefix and localname string
+ *
+ * \param qname The qname to split
+ * \param doc The document context to create the prefix/localname in
+ * \param prefix Pointer to location to receive prefix
+ * \param localname Pointer to location to receive localname
+ * \return DOM_NO_ERR on success.
+ *
+ * If there is no prefix present in ::qname, then ::prefix will be NULL.
+ *
+ * ::prefix and ::localname will be referenced. The caller should unreference
+ * them once finished.
+ */
+dom_exception _dom_namespace_split_qname(struct dom_string *qname,
+ struct dom_document *doc, struct dom_string **prefix,
+ struct dom_string **localname)
+{
+ const uint8_t *qname_data, *c, *local_data;
+ size_t qname_len;
+ size_t local_len;
+ size_t prefix_len;
+ struct dom_string *p = NULL;
+ struct dom_string *l;
+ dom_exception err;
+
+ dom_string_get_data(qname, &qname_data, &qname_len);
+
+ /* Find colon, if any */
+ /** \todo assumes ASCII-compatible encoding */
+ for (c = qname_data; c != qname_data + qname_len; c++) {
+ if (*c == (const uint8_t) ':')
+ break;
+ }
+
+ if (c == qname_data + qname_len) {
+ /* None found => no prefix */
+ local_data = qname_data;
+ local_len = qname_len;
+ prefix_len = 0;
+ } else {
+ /* Found one => prefix */
+ local_data = ++c;
+ local_len = qname_len - (c - qname_data);
+ prefix_len = (c - qname_data - 1 /* ':' */);
+ }
+
+ /* Create prefix, if one exists */
+ if (prefix_len > 0) {
+ err = dom_string_create_from_ptr(doc, qname_data,
+ prefix_len, &p);
+ if (err != DOM_NO_ERR) {
+ return err;
+ }
+ }
+
+ /* Create localname */
+ err = dom_string_create_from_ptr(doc, local_data, local_len, &l);
+ if (err != DOM_NO_ERR) {
+ if (p != NULL) {
+ dom_string_unref(p);
+ }
+ return err;
+ }
+
+ *prefix = p;
+ *localname = l;
+
+ return DOM_NO_ERR;
+}
+
diff --git a/src/utils/namespace.h b/src/utils/namespace.h
new file mode 100644
index 0000000..0bc5093
--- /dev/null
+++ b/src/utils/namespace.h
@@ -0,0 +1,33 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
+ */
+
+#ifndef dom_utils_namespace_h_
+#define dom_utils_namespace_h_
+
+#include <dom/functypes.h>
+#include <dom/core/exceptions.h>
+
+struct dom_document;
+struct dom_string;
+
+/* Initialise the namespace component */
+dom_exception _dom_namespace_initialise(dom_alloc alloc, void *pw);
+
+/* Finalise the namespace component */
+dom_exception _dom_namespace_finalise(void);
+
+/* Ensure a QName is valid */
+dom_exception _dom_namespace_validate_qname(struct dom_string *qname,
+ struct dom_string *namespace);
+
+/* Split a QName into a namespace prefix and localname string */
+dom_exception _dom_namespace_split_qname(struct dom_string *qname,
+ struct dom_document *doc, struct dom_string **prefix,
+ struct dom_string **localname);
+
+#endif
+
diff --git a/src/utils/utils.h b/src/utils/utils.h
index ae861c7..9ec8176 100644
--- a/src/utils/utils.h
+++ b/src/utils/utils.h
@@ -5,8 +5,8 @@
* Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
*/
-#ifndef dom_utils_h_
-#define dom_utils_h_
+#ifndef dom_utils_utils_h_
+#define dom_utils_utils_h_
#ifndef max
#define max(a,b) ((a)>(b)?(a):(b))