summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBo Yang <struggleyb.nku@gmail.com>2009-08-11 11:17:23 +0000
committerBo Yang <struggleyb.nku@gmail.com>2009-08-11 11:17:23 +0000
commit399da01ae4eb5c5e3e9349bacc2063c946c3d4a1 (patch)
tree433c8bcde94fc7a6e6f2e5cbf23842a84db98146 /src
parenteec057c7437e19b59ca1e698ce548cb56ce37240 (diff)
downloadlibdom-399da01ae4eb5c5e3e9349bacc2063c946c3d4a1.tar.gz
libdom-399da01ae4eb5c5e3e9349bacc2063c946c3d4a1.tar.bz2
Merge the branches/struggleyb/libdom-remain back to trunk.
svn path=/trunk/dom/; revision=9191
Diffstat (limited to 'src')
-rw-r--r--src/bootstrap/Makefile2
-rw-r--r--src/bootstrap/implementation.c423
-rw-r--r--src/bootstrap/implementation.h14
-rw-r--r--src/bootstrap/implregistry.c71
-rw-r--r--src/bootstrap/init_fini.c19
-rw-r--r--src/core/Makefile13
-rw-r--r--src/core/attr.c342
-rw-r--r--src/core/attr.h98
-rw-r--r--src/core/cdatasection.c66
-rw-r--r--src/core/cdatasection.h24
-rw-r--r--src/core/characterdata.c83
-rw-r--r--src/core/characterdata.h29
-rw-r--r--src/core/comment.c67
-rw-r--r--src/core/comment.h23
-rw-r--r--src/core/doc_fragment.c95
-rw-r--r--src/core/doc_fragment.h23
-rw-r--r--src/core/document.c1001
-rw-r--r--src/core/document.h108
-rw-r--r--src/core/document_type.c224
-rw-r--r--src/core/document_type.h28
-rw-r--r--src/core/element.c2031
-rw-r--r--src/core/element.h108
-rw-r--r--src/core/entity_ref.c98
-rw-r--r--src/core/entity_ref.h31
-rw-r--r--src/core/implementation.c25
-rw-r--r--src/core/impllist.c19
-rw-r--r--src/core/namednodemap.c361
-rw-r--r--src/core/namednodemap.h50
-rw-r--r--src/core/node.c1147
-rw-r--r--src/core/node.h144
-rw-r--r--src/core/nodelist.c214
-rw-r--r--src/core/nodelist.h26
-rw-r--r--src/core/pi.c65
-rw-r--r--src/core/pi.h22
-rw-r--r--src/core/string.c358
-rw-r--r--src/core/string.h32
-rw-r--r--src/core/text.c320
-rw-r--r--src/core/text.h46
-rw-r--r--src/core/typeinfo.c80
-rw-r--r--src/utils/Makefile3
-rw-r--r--src/utils/character_valid.c217
-rw-r--r--src/utils/character_valid.h54
-rw-r--r--src/utils/hashtable.c492
-rw-r--r--src/utils/hashtable.h42
-rw-r--r--src/utils/list.h61
-rw-r--r--src/utils/namespace.c71
-rw-r--r--src/utils/namespace.h7
-rw-r--r--src/utils/resource_mgr.c105
-rw-r--r--src/utils/resource_mgr.h45
-rw-r--r--src/utils/validate.c177
-rw-r--r--src/utils/validate.h26
51 files changed, 7278 insertions, 1952 deletions
diff --git a/src/bootstrap/Makefile b/src/bootstrap/Makefile
index 820a4f4..e969d87 100644
--- a/src/bootstrap/Makefile
+++ b/src/bootstrap/Makefile
@@ -1,3 +1,3 @@
-DIR_SOURCES := implregistry.c init_fini.c
+DIR_SOURCES := implregistry.c init_fini.c implementation.c
include build/makefiles/Makefile.subdir
diff --git a/src/bootstrap/implementation.c b/src/bootstrap/implementation.c
new file mode 100644
index 0000000..d14fa5b
--- /dev/null
+++ b/src/bootstrap/implementation.c
@@ -0,0 +1,423 @@
+/*
+ * 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>
+ * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
+ */
+
+/**
+ * Note: The DOMImplementation Object here is a singleton object. It is
+ * initialised when the libDOM is initialised, it registers itself into
+ * the implreg and clients of it can get it by calling:
+ *
+ * dom_implregistry_get_dom_implementation or
+ * dom_implregistry_get_dom_implementation_list
+ *
+ */
+
+#include <dom/bootstrap/implpriv.h>
+#include <dom/bootstrap/implregistry.h>
+#include <dom/dom.h>
+
+#include <libwapcaplet/libwapcaplet.h>
+
+#include "core/node.h"
+#include "core/document_type.h"
+
+#include "utils/utils.h"
+#include "utils/validate.h"
+#include "utils/namespace.h"
+
+#include "bootstrap/implementation.h"
+
+static dom_alloc _alloc;
+static void *_pw;
+
+static dom_exception impl_get_dom_implementation(
+ struct dom_string *features,
+ struct dom_implementation **impl);
+static dom_exception impl_get_dom_implementation_list(
+ struct dom_string *features,
+ struct dom_implementation_list **list);
+
+static dom_exception impl_implementation_has_feature(
+ struct dom_implementation *impl,
+ struct dom_string *feature,
+ struct dom_string *version,
+ bool *result);
+static dom_exception impl_implementation_create_document_type(
+ struct dom_implementation *impl,
+ struct dom_string *qname,
+ struct dom_string *public_id,
+ struct dom_string *system_id,
+ dom_alloc alloc, void *pw, struct lwc_context_s *ctx,
+ struct dom_document_type **doctype);
+static dom_exception impl_implementation_create_document(
+ struct dom_implementation *impl,
+ struct dom_string *namespace,
+ struct dom_string *qname,
+ struct dom_document_type *doctype,
+ dom_alloc alloc, void *pw, struct lwc_context_s *ctx,
+ struct dom_document **doc);
+static dom_exception impl_implementation_get_feature(
+ struct dom_implementation *impl,
+ struct dom_string *feature,
+ struct dom_string *version,
+ void **object);
+static void dom_implementation_destroy(struct dom_implementation *impl);
+
+
+static struct dom_implementation_source dom_impl_src = {
+ impl_get_dom_implementation,
+ impl_get_dom_implementation_list
+};
+
+static struct dom_implementation dom_impl = {
+ impl_implementation_has_feature,
+ impl_implementation_create_document_type,
+ impl_implementation_create_document,
+ impl_implementation_get_feature,
+ dom_implementation_destroy,
+ 0
+};
+
+/**
+ * Get a DOM implementation that supports the requested features
+ *
+ * \param features String containing required features
+ * \param impl Pointer to location to receive implementation
+ * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion
+ *
+ * Any memory allocated by this call should be allocated using
+ * the provided memory (de)allocation function. The implementation's
+ * destroy() method will be called once it is no longer used.
+ *
+ * The implementation will be referenced, so the client need not
+ * do this explicitly. The client must unref the implementation
+ * once it has finished with it.
+ */
+dom_exception impl_get_dom_implementation(
+ struct dom_string *features,
+ struct dom_implementation **impl)
+{
+ UNUSED(features);
+
+ dom_impl.refcnt++;
+
+ *impl = &dom_impl;
+
+ return DOM_NO_ERR;
+}
+
+/**
+ * Get a list of DOM implementations that support the requested
+ * features
+ *
+ * \param features String containing required features
+ * \param list Pointer to location to receive list
+ * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion
+ *
+ * Any memory allocated by this call should be allocated using
+ * the provided memory (de)allocation function. The ::alloc/::pw
+ * pair must be stored on the list object, such that the list
+ * and its contents may be freed once they are no longer needed.
+ *
+ * List nodes reference the implementation objects they point to.
+ *
+ * The list will be referenced, so the client need not do this
+ * explicitly. The client must unref the list once it has finished
+ * with it.
+ */
+dom_exception impl_get_dom_implementation_list(
+ struct dom_string *features,
+ struct dom_implementation_list **list)
+{
+ struct dom_implementation_list *l;
+ struct dom_implementation_list_item *i;
+
+ UNUSED(features);
+
+ l = _alloc(NULL, sizeof(struct dom_implementation_list), _pw);
+ if (l == NULL)
+ return DOM_NO_MEM_ERR;
+
+ i = _alloc(NULL, sizeof(struct dom_implementation_list_item), _pw);
+ if (i == NULL) {
+ _alloc(l, 0, _pw);
+ return DOM_NO_MEM_ERR;
+ }
+
+ i->impl = &dom_impl;
+ i->next = NULL;
+ i->prev = NULL;
+
+ l->head = i;
+
+ l->refcnt = 1;
+
+ *list = l;
+
+ return DOM_NO_ERR;
+}
+
+/**
+ * Test whether a DOM implementation implements a specific feature
+ * and version
+ *
+ * \param impl The DOM implementation to query
+ * \param feature The feature to test for
+ * \param version The version number of the feature to test for
+ * \param result Pointer to location to receive result
+ * \return DOM_NO_ERR.
+ */
+dom_exception impl_implementation_has_feature(
+ struct dom_implementation *impl,
+ struct dom_string *feature,
+ struct dom_string *version,
+ bool *result)
+{
+ UNUSED(impl);
+ UNUSED(feature);
+ UNUSED(version);
+ UNUSED(result);
+
+ return DOM_NOT_SUPPORTED_ERR;
+}
+
+/**
+ * Create a document type node
+ *
+ * \param impl The implementation to create the node
+ * \param qname The qualified name of the document type
+ * \param public_id The external subset public identifier
+ * \param system_id The external subset system identifier
+ * \param doctype Pointer to location to receive result
+ * \return DOM_NO_ERR on success,
+ * DOM_INVALID_CHARACTER_ERR if ::qname is invalid,
+ * DOM_NAMESPACE_ERR if ::qname is malformed.
+ *
+ * Any memory allocated by this call should be allocated using
+ * the provided memory (de)allocation function.
+ *
+ * The doctype will be referenced, so the client need not do this
+ * explicitly. The client must unref the doctype once it has
+ * finished with it.
+ */
+dom_exception impl_implementation_create_document_type(
+ struct dom_implementation *impl,
+ struct dom_string *qname,
+ struct dom_string *public_id,
+ struct dom_string *system_id,
+ dom_alloc alloc, void *pw, struct lwc_context_s *ctx,
+ struct dom_document_type **doctype)
+{
+ struct dom_document_type *d;
+ struct dom_string *prefix = NULL, *lname = NULL;
+ dom_exception err;
+
+ UNUSED(impl);
+
+ if (qname != NULL && _dom_validate_name(qname) == false)
+ return DOM_INVALID_CHARACTER_ERR;
+
+ err = _dom_namespace_split_qname(qname, &prefix, &lname);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ if ((prefix != NULL && _dom_validate_ncname(prefix) == false) ||
+ (lname != NULL && _dom_validate_ncname(lname) == false))
+ return DOM_NAMESPACE_ERR;
+
+ /* Create the doctype */
+ err = dom_document_type_create(qname, public_id, system_id,
+ alloc, pw, ctx, &d);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ *doctype = d;
+ if (prefix != NULL)
+ dom_string_unref(prefix);
+ if (lname != NULL)
+ dom_string_unref(lname);
+
+ return DOM_NO_ERR;
+}
+
+/**
+ * Create a document node
+ *
+ * \param impl The implementation to create the node
+ * \param namespace The namespace URI of the document element
+ * \param qname The qualified name of the document element
+ * \param doctype The type of document to create
+ * \param doc Pointer to location to receive result
+ * \return DOM_NO_ERR on success,
+ * DOM_INVALID_CHARACTER_ERR if ::qname is invalid,
+ * DOM_NAMESPACE_ERR if ::qname is malformed, or if
+ * ::qname has a prefix and
+ * ::namespace is NULL, or if
+ * ::qname is NULL and ::namespace
+ * is non-NULL, or if ::qname has
+ * a prefix "xml" and ::namespace
+ * is not
+ * "http://www.w3.org/XML/1998/namespace",
+ * or if ::impl does not support
+ * the "XML" feature and
+ * ::namespace is non-NULL,
+ * DOM_WRONG_DOCUMENT_ERR if ::doctype is already being
+ * used by a document, or if it
+ * was not created by ::impl,
+ * DOM_NOT_SUPPORTED_ERR if ::impl does not support the
+ * feature "XML" and the language
+ * exposed through Document does
+ * not support XML namespaces.
+ *
+ * Any memory allocated by this call should be allocated using
+ * the provided memory (de)allocation function.
+ *
+ * The document will be referenced, so the client need not do this
+ * explicitly. The client must unref the document once it has
+ * finished with it.
+ */
+dom_exception impl_implementation_create_document(
+ struct dom_implementation *impl,
+ struct dom_string *namespace,
+ struct dom_string *qname,
+ struct dom_document_type *doctype,
+ dom_alloc alloc, void *pw, struct lwc_context_s *ctx,
+ struct dom_document **doc)
+{
+ struct dom_document *d;
+ dom_exception err;
+
+ if (qname != NULL && _dom_validate_name(qname) == false)
+ return DOM_INVALID_CHARACTER_ERR;
+
+ err = _dom_namespace_validate_qname(qname, namespace);
+ if (err != DOM_NO_ERR)
+ return DOM_NAMESPACE_ERR;
+
+ if (doctype != NULL) {
+ if (dom_node_get_parent(doctype) != NULL ||
+ _dom_document_type_get_impl(doctype) !=
+ impl)
+ return DOM_WRONG_DOCUMENT_ERR;
+ }
+
+ /* Create document object */
+ err = dom_document_create(impl, alloc, pw, ctx, &d);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ /* Set its doctype, if necessary */
+ if (doctype != NULL) {
+ struct dom_node *ins_doctype = NULL;
+
+ err = dom_node_append_child((struct dom_node *) d,
+ (struct dom_node *) doctype, &ins_doctype);
+ if (err != DOM_NO_ERR) {
+ dom_node_unref((struct dom_node *) d);
+ return err;
+ }
+
+ /* Not interested in inserted doctype */
+ if (ins_doctype != NULL)
+ dom_node_unref(ins_doctype);
+ }
+
+ /* Create root element and attach it to document */
+ if (qname != NULL) {
+ struct dom_element *e;
+ struct dom_node *inserted;
+
+ err = dom_document_create_element_ns(d, namespace, qname, &e);
+ if (err != DOM_NO_ERR) {
+ dom_node_unref((struct dom_node *) d);
+ return err;
+ }
+
+ err = dom_node_append_child((struct dom_node *) d,
+ (struct dom_node *) e, &inserted);
+ if (err != DOM_NO_ERR) {
+ dom_node_unref((struct dom_node *) e);
+ dom_node_unref((struct dom_node *) d);
+ return err;
+ }
+
+ /* No longer interested in inserted node */
+ dom_node_unref(inserted);
+
+ /* Done with element */
+ dom_node_unref((struct dom_node *) e);
+ }
+
+ *doc = d;
+
+ return DOM_NO_ERR;
+}
+
+/**
+ * Retrieve a specialized object which implements the specified
+ * feature and version
+ *
+ * \param impl The implementation to create the object
+ * \param feature The requested feature
+ * \param version The version number of the feature
+ * \param object Pointer to location to receive object
+ * \return DOM_NO_ERR.
+ *
+ * Any memory allocated by this call should be allocated using
+ * the provided memory (de)allocation function.
+ */
+dom_exception impl_implementation_get_feature(
+ struct dom_implementation *impl,
+ struct dom_string *feature,
+ struct dom_string *version,
+ void **object)
+{
+ UNUSED(impl);
+ UNUSED(feature);
+ UNUSED(version);
+ UNUSED(object);
+
+ return DOM_NOT_SUPPORTED_ERR;
+}
+
+/**
+ * Destroy a DOM implementation instance
+ *
+ * \param impl The instance to destroy
+ */
+void dom_implementation_destroy(struct dom_implementation *impl)
+{
+ UNUSED(impl);
+
+ /* Nothing to do -- we're statically allocated */
+}
+
+/**
+ * Initialise the DOM implementation
+ *
+ * \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_implementation_initialise(dom_alloc alloc, void *pw)
+{
+ _alloc = alloc;
+ _pw = pw;
+
+ return dom_register_source(&dom_impl_src);
+}
+
+/**
+ * Finalise the DOM implementation
+ */
+void _dom_implementation_finalise(void)
+{
+ _alloc = NULL;
+ _pw = NULL;
+}
+
+
diff --git a/src/bootstrap/implementation.h b/src/bootstrap/implementation.h
new file mode 100644
index 0000000..f62077c
--- /dev/null
+++ b/src/bootstrap/implementation.h
@@ -0,0 +1,14 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
+ */
+
+#ifndef dom_bootstrap_implementation_h_
+#define dom_bootstrap_implementation_h_
+
+dom_exception _dom_implementation_initialise(dom_alloc alloc, void *pw);
+void _dom_implementation_finalise(void);
+
+#endif
diff --git a/src/bootstrap/implregistry.c b/src/bootstrap/implregistry.c
index 9407ee1..91e4068 100644
--- a/src/bootstrap/implregistry.c
+++ b/src/bootstrap/implregistry.c
@@ -11,6 +11,9 @@
#include <dom/bootstrap/implregistry.h>
#include <dom/core/impllist.h>
+#include <dom/core/implementation.h>
+
+void dom_implementation_list_destroy(struct dom_implementation_list *list);
/**
* Item in list of registered DOM implementation sources
@@ -23,14 +26,30 @@ struct dom_impl_src_item {
};
static struct dom_impl_src_item *sources; /**< List of registered sources */
+static dom_alloc alloc;
+static void *pw;
+
+/**
+ * Initialise the implementation registry
+ *
+ * \param allocator The memory allocator
+ * \param ptr Private data pointer of allocator
+ * \return DOM_NO_ERR on success
+ */
+dom_exception dom_implregistry_initialise(
+ dom_alloc allocator, void *ptr)
+{
+ alloc = allocator;
+ pw = ptr;
+
+ return DOM_NO_ERR;
+}
/**
* Retrieve a DOM implementation from the registry
*
* \param features String containing required features
* \param impl Pointer to location to receive implementation
- * \param alloc Function to (de)allocate memory
- * \param pw Pointer to client-specific private data
* \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion
*
* Any memory allocated by this call should be allocated using
@@ -43,16 +62,14 @@ static struct dom_impl_src_item *sources; /**< List of registered sources */
*/
dom_exception dom_implregistry_get_dom_implementation(
struct dom_string *features,
- struct dom_implementation **impl,
- dom_alloc alloc, void *pw)
+ struct dom_implementation **impl)
{
struct dom_impl_src_item *item;
struct dom_implementation *found = NULL;
dom_exception err;
for (item = sources; item; item = item->next) {
- err = item->source->get_dom_implementation(features, &found,
- alloc, pw);
+ err = item->source->get_dom_implementation(features, &found);
if (err != DOM_NO_ERR)
return err;
@@ -71,14 +88,10 @@ dom_exception dom_implregistry_get_dom_implementation(
*
* \param features String containing required features
* \param list Pointer to location to receive list
- * \param alloc Function to (de)allocate memory
- * \param pw Pointer to client-specific private data
* \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion
*
* Any memory allocated by this call should be allocated using
- * the provided memory (de)allocation function. The ::alloc/::pw
- * pair must be stored on the list object, such that the list
- * and its contents may be freed once they are no longer needed.
+ * the provided memory (de)allocation function.
*
* List nodes reference the implementation objects they point to.
*
@@ -88,8 +101,7 @@ dom_exception dom_implregistry_get_dom_implementation(
*/
dom_exception dom_implregistry_get_dom_implementation_list(
struct dom_string *features,
- struct dom_implementation_list **list,
- dom_alloc alloc, void *pw)
+ struct dom_implementation_list **list)
{
struct dom_implementation_list *l;
struct dom_impl_src_item *item;
@@ -100,16 +112,15 @@ dom_exception dom_implregistry_get_dom_implementation_list(
return DOM_NO_MEM_ERR;
l->head = NULL;
- l->alloc = alloc;
- l->pw = pw;
l->refcnt = 1;
+ l->destroy = dom_implementation_list_destroy;
for (item = sources; item; item = item->next) {
struct dom_implementation_list *plist = NULL;
struct dom_implementation_list_item *plast = NULL;
err = item->source->get_dom_implementation_list(features,
- &plist, alloc, pw);
+ &plist);
if (err != DOM_NO_ERR) {
dom_implementation_list_unref(l);
return err;
@@ -156,12 +167,9 @@ dom_exception dom_implregistry_get_dom_implementation_list(
* Register a DOM implementation source with the DOM library
*
* \param source The implementation source to register
- * \param alloc Memory (de)allocation function
- * \param pw Pointer to client-specific private data
* \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion.
*/
-dom_exception dom_register_source(struct dom_implementation_source *source,
- dom_alloc alloc, void *pw)
+dom_exception dom_register_source(struct dom_implementation_source *source)
{
struct dom_impl_src_item *item;
@@ -182,3 +190,26 @@ dom_exception dom_register_source(struct dom_implementation_source *source,
return DOM_NO_ERR;
}
+/**
+ * Destroy a dom_implementation_list
+ *
+ * \param list The list to destory
+ */
+void dom_implementation_list_destroy(struct dom_implementation_list *list)
+{
+ struct dom_implementation_list_item *i, *j;
+
+ /* Destroy all list entries */
+ for (i = list->head; i; i = j) {
+ j = i->next;
+
+ /* Unreference the implementation */
+ dom_implementation_unref(i->impl);
+
+ /* And free the entry */
+ alloc(i, 0, pw);
+ }
+
+ /* Free the list object */
+ alloc(list, 0, pw);
+}
diff --git a/src/bootstrap/init_fini.c b/src/bootstrap/init_fini.c
index a5a62a1..f3c7290 100644
--- a/src/bootstrap/init_fini.c
+++ b/src/bootstrap/init_fini.c
@@ -8,9 +8,10 @@
#include <stdbool.h>
#include <dom/bootstrap/init_fini.h>
+#include <dom/bootstrap/implregistry.h>
-#include "core/document.h"
#include "utils/namespace.h"
+#include "bootstrap/implementation.h"
static bool __initialised;
@@ -32,16 +33,21 @@ dom_exception dom_initialise(dom_alloc alloc, void *pw)
return DOM_NO_ERR;
}
- err = _dom_document_initialise(alloc, pw);
+ err = _dom_namespace_initialise(alloc, pw);
if (err != DOM_NO_ERR) {
return err;
}
- err = _dom_namespace_initialise(alloc, pw);
+ err = dom_implregistry_initialise(alloc, pw);
if (err != DOM_NO_ERR) {
return err;
}
+ err = _dom_implementation_initialise(alloc, pw);
+ if (err != DOM_NO_ERR) {
+ return err;
+ }
+
__initialised = true;
return DOM_NO_ERR;
@@ -63,12 +69,9 @@ dom_exception dom_finalise(void)
return DOM_NO_ERR;
}
- err = _dom_namespace_finalise();
- if (err != DOM_NO_ERR) {
- return err;
- }
+ _dom_implementation_finalise();
- err = _dom_document_finalise();
+ err = _dom_namespace_finalise();
if (err != DOM_NO_ERR) {
return err;
}
diff --git a/src/core/Makefile b/src/core/Makefile
index 9abadad..46cb48d 100644
--- a/src/core/Makefile
+++ b/src/core/Makefile
@@ -1,8 +1,11 @@
# Sources
-DIR_SOURCES := attr.c cdatasection.c characterdata.c comment.c \
- document.c document_type.c doc_fragment.c \
- element.c entity_ref.c implementation.c impllist.c \
- namednodemap.c node.c nodelist.c \
- pi.c string.c text.c
+DIR_SOURCES := \
+ string.c node.c \
+ attr.c characterdata.c element.c \
+ implementation.c impllist.c \
+ text.c typeinfo.c comment.c \
+ namednodemap.c nodelist.c \
+ cdatasection.c document_type.c entity_ref.c pi.c \
+ doc_fragment.c document.c
include build/makefiles/Makefile.subdir
diff --git a/src/core/attr.c b/src/core/attr.c
index 9fbb06f..df95482 100644
--- a/src/core/attr.c
+++ b/src/core/attr.c
@@ -3,10 +3,12 @@
* Licensed under the MIT License,
* http://www.opensource.org/licenses/mit-license.php
* Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
*/
#include <stddef.h>
#include <string.h>
+#include <assert.h>
#include <dom/core/attr.h>
#include <dom/core/document.h>
@@ -25,24 +27,34 @@ struct dom_element;
* DOM node attribute
*/
struct dom_attr {
- struct dom_node_internal base; /**< Base node */
+ struct dom_node_internal base; /**< Base node */
- bool specified; /**< Whether attribute was specified
- * or defaulted */
+ bool specified; /**< Whether the attribute is specified
+ * or default */
struct dom_type_info *schema_type_info; /**< Type information */
- bool is_id; /**< Attribute is of type ID */
+ bool is_id; /**< Whether this attribute is a ID attribute */
};
-/* The vtable for dom attr node */
+/* The vtable for dom_attr node */
static struct dom_attr_vtable attr_vtable = {
{
- DOM_NODE_VTABLE
+ DOM_NODE_VTABLE_ATTR
},
DOM_ATTR_VTABLE
};
+/* The protected vtable for dom_attr */
+static struct dom_node_protect_vtable attr_protect_vtable = {
+ DOM_ATTR_PROTECT_VTABLE
+};
+
+
+/* -------------------------------------------------------------------- */
+
+/* Constructor and destructor */
+
/**
* Create an attribute node
*
@@ -50,43 +62,69 @@ static struct dom_attr_vtable attr_vtable = {
* \param name The (local) name of the node to create
* \param namespace The namespace URI of the attribute, or NULL
* \param prefix The namespace prefix of the attribute, or NULL
+ * \param specified Whtether this attribute is specified
* \param result Pointer to location to receive created attribute
* \return DOM_NO_ERR on success,
- * DOM_INVALID_CHARACTER_ERR if ::name is invalid,
* DOM_NO_MEM_ERR on memory exhaustion.
*
- * ::doc and ::name will have their reference counts increased.
+ * ::doc and ::name will have their reference counts increased. The
+ * caller should make sure that ::name is a valid NCName here.
*
* The returned attribute will already be referenced.
*/
-dom_exception dom_attr_create(struct dom_document *doc,
- struct dom_string *name, struct dom_string *namespace,
- struct dom_string *prefix, struct dom_attr **result)
+dom_exception _dom_attr_create(struct dom_document *doc,
+ struct lwc_string_s *name, struct lwc_string_s *namespace,
+ struct lwc_string_s *prefix, bool specified,
+ struct dom_attr **result)
{
struct dom_attr *a;
dom_exception err;
- /** \todo Sanity check the attribute name */
-
- /* Allocate the element */
- a = dom_document_alloc(doc, NULL, sizeof(struct dom_attr));
+ /* Allocate the attribute node */
+ a = _dom_document_alloc(doc, NULL, sizeof(struct dom_attr));
if (a == NULL)
return DOM_NO_MEM_ERR;
/* Initialise the vtable */
a->base.base.vtable = &attr_vtable;
- a->base.destroy = _dom_attr_destroy;
+ a->base.vtable = &attr_protect_vtable;
+
+ /* Initialise the class */
+ err = _dom_attr_initialise(a, doc, name, namespace, prefix, specified,
+ result);
+ if (err != DOM_NO_ERR) {
+ _dom_document_alloc(doc, a, 0);
+ return err;
+ }
+ return DOM_NO_ERR;
+}
+
+/**
+ * Initialise a dom_attr
+ *
+ * \param a The dom_attr
+ * \param doc The document
+ * \param name The name of this attribute node
+ * \param namespace The namespace of this attribute
+ * \param prefix The prefix
+ * \param specified Whether this node is a specified one
+ * \param result The returned node
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ */
+dom_exception _dom_attr_initialise(dom_attr *a,
+ struct dom_document *doc, struct lwc_string_s *name,
+ struct lwc_string_s *namespace, struct lwc_string_s *prefix,
+ bool specified, struct dom_attr **result)
+{
+ dom_exception err;
- /* Initialise the base class */
- err = dom_node_initialise(&a->base, doc, DOM_ATTRIBUTE_NODE,
+ err = _dom_node_initialise(&a->base, doc, DOM_ATTRIBUTE_NODE,
name, NULL, namespace, prefix);
if (err != DOM_NO_ERR) {
- dom_document_alloc(doc, a, 0);
return err;
}
- /* Perform our type-specific initialisation */
- a->specified = false;
+ a->specified = specified;
a->schema_type_info = NULL;
a->is_id = false;
@@ -96,61 +134,48 @@ dom_exception dom_attr_create(struct dom_document *doc,
}
/**
- * Destroy an attribute node
+ * The destructor of dom_attr
*
- * \param doc The owning document
- * \param attr The attribute to destroy
- *
- * The contents of ::attr will be destroyed and ::attr will be freed
+ * \param doc The owner document
+ * \param attr The attribute
*/
-void dom_attr_destroy(struct dom_document *doc, struct dom_attr *attr)
+void _dom_attr_finalise(dom_document *doc, dom_attr *attr)
{
- struct dom_node_internal *c, *d;
-
- /* Destroy children of this node */
- for (c = attr->base.first_child; c != NULL; c = d) {
- d = c->next;
-
- /* Detach child */
- c->parent = NULL;
-
- if (c->refcnt > 0) {
- /* Something is using this child */
-
- /** \todo add to list of nodes pending deletion */
-
- continue;
- }
-
- /* Detach from sibling list */
- c->previous = NULL;
- c->next = NULL;
-
- dom_node_destroy(c);
- }
-
/* Now, clean up this node and destroy it */
if (attr->schema_type_info != NULL) {
/** \todo destroy schema type info */
}
- dom_node_finalise(doc, &attr->base);
-
- dom_document_alloc(doc, attr, 0);
+ _dom_node_finalise(doc, &attr->base);
}
-void _dom_attr_destroy(dom_node_internal *node)
+/**
+ * Destroy an attribute node
+ *
+ * \param doc The owning document
+ * \param attr The attribute to destroy
+ *
+ * The contents of ::attr will be destroyed and ::attr will be freed
+ */
+void _dom_attr_destroy(struct dom_document *doc, struct dom_attr *attr)
{
- UNUSED(node);
+ _dom_attr_finalise(doc, attr);
+
+ _dom_document_alloc(doc, attr, 0);
}
+
+/* -------------------------------------------------------------------- */
+
+/* The public virtual functions */
+
/**
* Retrieve an attribute's name
*
* \param attr Attribute to retrieve name from
* \param result Pointer to location to receive result
- * \return DOM_NO_ERR.
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure
*
* The returned string will have its reference count increased. It is
* the responsibility of the caller to unref the string once it has
@@ -164,7 +189,7 @@ dom_exception _dom_attr_get_name(struct dom_attr *attr,
}
/**
- * Determine if attribute was specified or defaulted
+ * Determine if attribute was specified or default
*
* \param attr Attribute to inspect
* \param result Pointer to location to receive result
@@ -182,7 +207,7 @@ dom_exception _dom_attr_get_specified(struct dom_attr *attr, bool *result)
*
* \param attr Attribute to retrieve value from
* \param result Pointer to location to receive result
- * \return DOM_NO_ERR.
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure
*
* The returned string will have its reference count increased. It is
* the responsibility of the caller to unref the string once it has
@@ -196,8 +221,8 @@ dom_exception _dom_attr_get_value(struct dom_attr *attr,
struct dom_string *value, *temp;
dom_exception err;
- err = dom_document_create_string(a->owner,
- (const uint8_t *) "", SLEN(""), &value);
+ err = _dom_document_create_string(a->owner,
+ NULL, 0, &value);
if (err != DOM_NO_ERR) {
return err;
}
@@ -221,7 +246,7 @@ dom_exception _dom_attr_get_value(struct dom_attr *attr,
struct dom_string *tr;
/* Get textual representation of entity */
- err = dom_entity_reference_get_textual_representation(
+ err = _dom_entity_reference_get_textual_representation(
(struct dom_entity_reference *) c,
&tr);
if (err != DOM_NO_ERR) {
@@ -285,24 +310,21 @@ dom_exception _dom_attr_set_value(struct dom_attr *attr,
/* Detach child */
c->parent = NULL;
- if (c->refcnt > 0) {
- /* Something is using this child */
-
- /** \todo add to list of nodes pending deletion */
-
- continue;
- }
-
/* Detach from sibling list */
c->previous = NULL;
c->next = NULL;
- dom_node_destroy(c);
+ dom_node_try_destroy(c);
}
/* And insert the text node as the value */
((struct dom_node_internal *) text)->parent = a;
a->first_child = a->last_child = (struct dom_node_internal *) text;
+ dom_node_unref(text);
+ dom_node_remove_pending(text);
+
+ /* Now the attribute node is specified */
+ attr->specified = true;
return DOM_NO_ERR;
}
@@ -336,7 +358,7 @@ dom_exception _dom_attr_get_owner(struct dom_attr *attr,
*
* \param attr The attribute to extract type information from
* \param result Pointer to location to receive result
- * \return DOM_NO_ERR.
+ * \return DOM_NOT_SUPPORTED_ERR, we don't support this API now.
*
* The returned type info will have its reference count increased. The caller
* should unref it once it has finished with it.
@@ -363,3 +385,179 @@ dom_exception _dom_attr_is_id(struct dom_attr *attr, bool *result)
return DOM_NO_ERR;
}
+
+/*------------- The overload virtual functions ------------------------*/
+
+/* Overload function of Node, please refer node.c for the detail of this
+ * function. */
+dom_exception _dom_attr_get_node_value(dom_node_internal *node,
+ struct dom_string **result)
+{
+ dom_attr *attr = (dom_attr *) node;
+
+ return _dom_attr_get_value(attr, result);
+}
+
+/* Overload function of Node, please refer node.c for the detail of this
+ * function. */
+dom_exception _dom_attr_clone_node(dom_node_internal *node, bool deep,
+ dom_node_internal **result)
+{
+ dom_exception err;
+ dom_attr *attr;
+
+ /* Discard the warnings */
+ UNUSED(deep);
+
+ /* Clone an Attr always clone all its children */
+ err = _dom_node_clone_node(node, true, result);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ attr = (dom_attr *) *result;
+ /* Clone an Attr always result a specified Attr,
+ * see DOM Level 3 Node.cloneNode */
+ attr->specified = true;
+
+ return DOM_NO_ERR;
+}
+
+/* Overload function of Node, please refer node.c for the detail of this
+ * function. */
+dom_exception _dom_attr_set_prefix(dom_node_internal *node,
+ struct dom_string *prefix)
+{
+ /* Really I don't know whether there should something
+ * special to do here */
+ return _dom_node_set_prefix(node, prefix);
+}
+
+/* Overload function of Node, please refer node.c for the detail of this
+ * function. */
+dom_exception _dom_attr_lookup_prefix(dom_node_internal *node,
+ struct dom_string *namespace, struct dom_string **result)
+{
+ struct dom_element *owner;
+ dom_exception err;
+
+ err = dom_attr_get_owner_element(node, &owner);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ if (owner == NULL) {
+ *result = NULL;
+ return DOM_NO_ERR;
+ }
+
+ return dom_node_lookup_prefix(owner, namespace, result);
+}
+
+/* Overload function of Node, please refer node.c for the detail of this
+ * function. */
+dom_exception _dom_attr_is_default_namespace(dom_node_internal *node,
+ struct dom_string *namespace, bool *result)
+{
+ struct dom_element *owner;
+ dom_exception err;
+
+ err = dom_attr_get_owner_element(node, &owner);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ if (owner == NULL) {
+ *result = false;
+ return DOM_NO_ERR;
+ }
+
+ return dom_node_is_default_namespace(owner, namespace, result);
+}
+
+/* Overload function of Node, please refer node.c for the detail of this
+ * function. */
+dom_exception _dom_attr_lookup_namespace(dom_node_internal *node,
+ struct dom_string *prefix, struct dom_string **result)
+{
+ struct dom_element *owner;
+ dom_exception err;
+
+ err = dom_attr_get_owner_element(node, &owner);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ if (owner == NULL) {
+ *result = NULL;
+ return DOM_NO_ERR;
+ }
+
+ return dom_node_lookup_namespace(owner, prefix, result);
+}
+
+
+/*----------------------------------------------------------------------*/
+
+/* The protected virtual functions */
+
+/* The virtual destroy function of this class */
+void __dom_attr_destroy(dom_node_internal *node)
+{
+ dom_document *doc = node->owner;
+
+ assert(doc != NULL);
+ _dom_attr_destroy(doc, (dom_attr *) node);
+}
+
+/* The memory allocator of this class */
+dom_exception _dom_attr_alloc(struct dom_document *doc,
+ struct dom_node_internal *n, struct dom_node_internal **ret)
+{
+ UNUSED(n);
+ dom_attr *a;
+
+ a = _dom_document_alloc(doc, NULL, sizeof(struct dom_attr));
+ if (a == NULL)
+ return DOM_NO_MEM_ERR;
+
+ *ret = (dom_node_internal *) a;
+ dom_node_set_owner(*ret, doc);
+
+ return DOM_NO_ERR;
+}
+
+/* The copy constructor of this class */
+dom_exception _dom_attr_copy(struct dom_node_internal *new,
+ struct dom_node_internal *old)
+{
+ dom_attr *na = (dom_attr *) new;
+ dom_attr *oa = (dom_attr *) old;
+
+ na->specified = oa->specified;
+ na->is_id = oa->is_id;
+
+ /* TODO: deal with dom_type_info, it get no definition ! */
+
+ return _dom_node_copy(new, old);
+}
+
+
+/**
+ * Set/Unset whether this attribute is a ID attribute
+ *
+ * \param attr The attribute
+ * \param is_id Whether it is a ID attribute
+ */
+void _dom_attr_set_isid(struct dom_attr *attr, bool is_id)
+{
+ attr->is_id = is_id;
+}
+
+/**
+ * Set/Unset whether the attribute is a specified one.
+ *
+ * \param attr The attribute node
+ * \param specified Whether this attribute is a specified one
+ */
+void _dom_attr_set_specified(struct dom_attr *attr, bool specified)
+{
+ attr->specified = specified;
+}
+
diff --git a/src/core/attr.h b/src/core/attr.h
index 2a3cd67..84b741f 100644
--- a/src/core/attr.h
+++ b/src/core/attr.h
@@ -13,26 +13,31 @@
struct dom_document;
struct dom_string;
struct dom_type_info;
+struct lwc_string_s;
-dom_exception dom_attr_create(struct dom_document *doc,
- struct dom_string *name, struct dom_string *namespace,
- struct dom_string *prefix, struct dom_attr **result);
-void dom_attr_destroy(struct dom_document *doc, struct dom_attr *attr);
-/* The virtual destroy function */
-void _dom_attr_destroy(dom_node_internal *node);
+dom_exception _dom_attr_create(struct dom_document *doc,
+ struct lwc_string_s *name, struct lwc_string_s *namespace,
+ struct lwc_string_s *prefix, bool specified,
+ struct dom_attr **result);
+void _dom_attr_destroy(struct dom_document *doc, struct dom_attr *attr);
+dom_exception _dom_attr_initialise(struct dom_attr *a,
+ struct dom_document *doc, struct lwc_string_s *name,
+ struct lwc_string_s *namespace, struct lwc_string_s *prefix,
+ bool specified, struct dom_attr **result);
+void _dom_attr_finalise(dom_document *doc, struct dom_attr *attr);
-/* Virtual functions for dom attr */
+/* Virtual functions for dom_attr */
dom_exception _dom_attr_get_name(struct dom_attr *attr,
- struct dom_string **result);
+ struct dom_string **result);
dom_exception _dom_attr_get_specified(struct dom_attr *attr, bool *result);
dom_exception _dom_attr_get_value(struct dom_attr *attr,
- struct dom_string **result);
+ struct dom_string **result);
dom_exception _dom_attr_set_value(struct dom_attr *attr,
- struct dom_string *value);
+ struct dom_string *value);
dom_exception _dom_attr_get_owner(struct dom_attr *attr,
- struct dom_element **result);
+ struct dom_element **result);
dom_exception _dom_attr_get_schema_type_info(struct dom_attr *attr,
- struct dom_type_info **result);
+ struct dom_type_info **result);
dom_exception _dom_attr_is_id(struct dom_attr *attr, bool *result);
#define DOM_ATTR_VTABLE \
@@ -44,4 +49,73 @@ dom_exception _dom_attr_is_id(struct dom_attr *attr, bool *result);
_dom_attr_get_schema_type_info, \
_dom_attr_is_id
+/* Overloading dom_node functions */
+dom_exception _dom_attr_get_node_value(dom_node_internal *node,
+ struct dom_string **result);
+dom_exception _dom_attr_clone_node(dom_node_internal *node, bool deep,
+ dom_node_internal **result);
+dom_exception _dom_attr_set_prefix(dom_node_internal *node,
+ struct dom_string *prefix);
+dom_exception _dom_attr_normalize(dom_node_internal *node);
+dom_exception _dom_attr_lookup_prefix(dom_node_internal *node,
+ struct dom_string *namespace, struct dom_string **result);
+dom_exception _dom_attr_is_default_namespace(dom_node_internal *node,
+ struct dom_string *namespace, bool *result);
+dom_exception _dom_attr_lookup_namespace(dom_node_internal *node,
+ struct dom_string *prefix, struct dom_string **result);
+#define DOM_NODE_VTABLE_ATTR \
+ _dom_node_get_node_name, \
+ _dom_attr_get_node_value, /*overload*/\
+ _dom_node_set_node_value, \
+ _dom_node_get_node_type, \
+ _dom_node_get_parent_node, \
+ _dom_node_get_child_nodes, \
+ _dom_node_get_first_child, \
+ _dom_node_get_last_child, \
+ _dom_node_get_previous_sibling, \
+ _dom_node_get_next_sibling, \
+ _dom_node_get_attributes, \
+ _dom_node_get_owner_document, \
+ _dom_node_insert_before, \
+ _dom_node_replace_child, \
+ _dom_node_remove_child, \
+ _dom_node_append_child, \
+ _dom_node_has_child_nodes, \
+ _dom_attr_clone_node, /*overload*/\
+ _dom_node_normalize, \
+ _dom_node_is_supported, \
+ _dom_node_get_namespace, \
+ _dom_node_get_prefix, \
+ _dom_attr_set_prefix, /*overload*/\
+ _dom_node_get_local_name, \
+ _dom_node_has_attributes, \
+ _dom_node_get_base, \
+ _dom_node_compare_document_position, \
+ _dom_node_get_text_content, \
+ _dom_node_set_text_content, \
+ _dom_node_is_same, \
+ _dom_attr_lookup_prefix, /*overload*/\
+ _dom_attr_is_default_namespace, /*overload*/\
+ _dom_attr_lookup_namespace, /*overload*/\
+ _dom_node_is_equal, \
+ _dom_node_get_feature, \
+ _dom_node_set_user_data, \
+ _dom_node_get_user_data
+
+/* The protected virtual functions */
+void __dom_attr_destroy(dom_node_internal *node);
+dom_exception _dom_attr_alloc(struct dom_document *doc,
+ struct dom_node_internal *n, struct dom_node_internal **ret);
+dom_exception _dom_attr_copy(struct dom_node_internal *new,
+ struct dom_node_internal *old);
+
+#define DOM_ATTR_PROTECT_VTABLE \
+ __dom_attr_destroy, \
+ _dom_attr_alloc, \
+ _dom_attr_copy
+
+
+inline void _dom_attr_set_isid(struct dom_attr *attr, bool is_id);
+inline void _dom_attr_set_specified(struct dom_attr *attr, bool specified);
+
#endif
diff --git a/src/core/cdatasection.c b/src/core/cdatasection.c
index 71d3d43..b470df2 100644
--- a/src/core/cdatasection.c
+++ b/src/core/cdatasection.c
@@ -3,11 +3,13 @@
* Licensed under the MIT License,
* http://www.opensource.org/licenses/mit-license.php
* Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
*/
#include "core/cdatasection.h"
#include "core/document.h"
#include "core/text.h"
+#include "utils/utils.h"
/**
* A DOM CDATA section
@@ -16,6 +18,10 @@ struct dom_cdata_section {
struct dom_text base; /**< Base node */
};
+static struct dom_node_protect_vtable cdata_section_protect_vtable = {
+ DOM_CDATA_SECTION_PROTECT_VTABLE
+};
+
/**
* Create a CDATA section
*
@@ -30,23 +36,27 @@ struct dom_cdata_section {
*
* The returned node will already be referenced.
*/
-dom_exception dom_cdata_section_create(struct dom_document *doc,
- struct dom_string *name, struct dom_string *value,
+dom_exception _dom_cdata_section_create(struct dom_document *doc,
+ struct lwc_string_s *name, struct dom_string *value,
struct dom_cdata_section **result)
{
struct dom_cdata_section *c;
dom_exception err;
/* Allocate the comment node */
- c = dom_document_alloc(doc, NULL, sizeof(struct dom_cdata_section));
+ c = _dom_document_alloc(doc, NULL, sizeof(struct dom_cdata_section));
if (c == NULL)
return DOM_NO_MEM_ERR;
+
+ /* Set up vtable */
+ ((dom_node_internal *) c)->base.vtable = &text_vtable;
+ ((dom_node_internal *) c)->vtable = &cdata_section_protect_vtable;
/* And initialise the node */
- err = dom_text_initialise(&c->base, doc, DOM_CDATA_SECTION_NODE,
- name, value);
+ err = _dom_cdata_section_initialise(&c->base, doc,
+ DOM_CDATA_SECTION_NODE, name, value);
if (err != DOM_NO_ERR) {
- dom_document_alloc(doc, c, 0);
+ _dom_document_alloc(doc, c, 0);
return err;
}
@@ -63,12 +73,50 @@ dom_exception dom_cdata_section_create(struct dom_document *doc,
*
* The contents of ::cdata will be destroyed and ::cdata will be freed.
*/
-void dom_cdata_section_destroy(struct dom_document *doc,
+void _dom_cdata_section_destroy(struct dom_document *doc,
struct dom_cdata_section *cdata)
{
/* Clean up base node contents */
- dom_text_finalise(doc, &cdata->base);
+ _dom_cdata_section_finalise(doc, &cdata->base);
/* Destroy the node */
- dom_document_alloc(doc, cdata, 0);
+ _dom_document_alloc(doc, cdata, 0);
+}
+
+/*--------------------------------------------------------------------------*/
+
+/* The protected virtual functions */
+
+/* The virtual destroy function of this class */
+void __dom_cdata_section_destroy(struct dom_node_internal *node)
+{
+ struct dom_document *doc;
+ doc = dom_node_get_owner(node);
+
+ _dom_cdata_section_destroy(doc, (struct dom_cdata_section *) node);
+}
+
+/* The memory allocator of this class */
+dom_exception _dom_cdata_section_alloc(struct dom_document *doc,
+ struct dom_node_internal *n, struct dom_node_internal **ret)
+{
+ UNUSED(n);
+ dom_cdata_section *a;
+
+ a = _dom_document_alloc(doc, NULL, sizeof(struct dom_cdata_section));
+ if (a == NULL)
+ return DOM_NO_MEM_ERR;
+
+ *ret = (dom_node_internal *) a;
+ dom_node_set_owner(*ret, doc);
+
+ return DOM_NO_ERR;
}
+
+/* The copy constructor of this class */
+dom_exception _dom_cdata_section_copy(struct dom_node_internal *new,
+ struct dom_node_internal *old)
+{
+ return _dom_characterdata_copy(new, old);
+}
+
diff --git a/src/core/cdatasection.h b/src/core/cdatasection.h
index 740c7d7..94d45a2 100644
--- a/src/core/cdatasection.h
+++ b/src/core/cdatasection.h
@@ -9,16 +9,34 @@
#define dom_internal_core_cdatasection_h_
#include <dom/core/exceptions.h>
+#include <dom/core/cdatasection.h>
+struct dom_node_internal;
struct dom_cdata_section;
struct dom_document;
struct dom_string;
+struct lwc_string_s;
-dom_exception dom_cdata_section_create(struct dom_document *doc,
- struct dom_string *name, struct dom_string *value,
+dom_exception _dom_cdata_section_create(struct dom_document *doc,
+ struct lwc_string_s *name, struct dom_string *value,
struct dom_cdata_section **result);
-void dom_cdata_section_destroy(struct dom_document *doc,
+void _dom_cdata_section_destroy(struct dom_document *doc,
struct dom_cdata_section *cdata);
+#define _dom_cdata_section_initialise _dom_text_initialise
+#define _dom_cdata_section_finalise _dom_text_finalise
+
+/* Following comes the protected vtable */
+void __dom_cdata_section_destroy(struct dom_node_internal *node);
+dom_exception _dom_cdata_section_alloc(struct dom_document *doc,
+ struct dom_node_internal *n, struct dom_node_internal **ret);
+dom_exception _dom_cdata_section_copy(struct dom_node_internal *new,
+ struct dom_node_internal *old);
+
+#define DOM_CDATA_SECTION_PROTECT_VTABLE \
+ __dom_cdata_section_destroy, \
+ _dom_cdata_section_alloc, \
+ _dom_cdata_section_copy
+
#endif
diff --git a/src/core/characterdata.c b/src/core/characterdata.c
index 6beecbe..f5b4094 100644
--- a/src/core/characterdata.c
+++ b/src/core/characterdata.c
@@ -3,8 +3,11 @@
* Licensed under the MIT License,
* http://www.opensource.org/licenses/mit-license.php
* Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
*/
+#include <assert.h>
+
#include <dom/core/characterdata.h>
#include <dom/core/string.h>
@@ -13,28 +16,28 @@
#include "core/node.h"
#include "utils/utils.h"
-/* The virtual functions for dom_characterdata */
-static struct dom_characterdata_vtable characterdata_vtable = {
+/* The virtual functions for dom_characterdata, we make this vtable
+ * public to each child class */
+struct dom_characterdata_vtable characterdata_vtable = {
{
DOM_NODE_VTABLE
},
DOM_CHARACTERDATA_VTABLE
};
-/**
- * Create a DOM characterdata node and compose the vtable
- *
- * Return The new constructed DOM characterdata node of NULL if fail
- */
-dom_characterdata *dom_characterdata_create(struct dom_document *doc)
+
+/* Create a DOM characterdata node and compose the vtable */
+dom_characterdata *_dom_characterdata_create(struct dom_document *doc)
{
- dom_characterdata *cdata = dom_document_alloc(doc, NULL,
+ dom_characterdata *cdata = _dom_document_alloc(doc, NULL,
sizeof(struct dom_characterdata));
if (cdata == NULL)
return NULL;
cdata->base.base.vtable = &characterdata_vtable;
+ cdata->base.vtable = NULL;
+
return cdata;
}
@@ -50,11 +53,11 @@ dom_characterdata *dom_characterdata_create(struct dom_document *doc)
*
* ::doc, ::name and ::value will have their reference counts increased.
*/
-dom_exception dom_characterdata_initialise(struct dom_characterdata *cdata,
+dom_exception _dom_characterdata_initialise(struct dom_characterdata *cdata,
struct dom_document *doc, dom_node_type type,
- struct dom_string *name, struct dom_string *value)
+ lwc_string *name, struct dom_string *value)
{
- return dom_node_initialise(&cdata->base, doc, type,
+ return _dom_node_initialise(&cdata->base, doc, type,
name, value, NULL, NULL);
}
@@ -66,12 +69,17 @@ dom_exception dom_characterdata_initialise(struct dom_characterdata *cdata,
*
* The contents of ::cdata will be cleaned up. ::cdata will not be freed.
*/
-void dom_characterdata_finalise(struct dom_document *doc,
+void _dom_characterdata_finalise(struct dom_document *doc,
struct dom_characterdata *cdata)
{
- dom_node_finalise(doc, &cdata->base);
+ _dom_node_finalise(doc, &cdata->base);
}
+
+/*----------------------------------------------------------------------*/
+
+/* The public virtual functions */
+
/**
* Retrieve data from a character data node
*
@@ -182,7 +190,7 @@ dom_exception _dom_characterdata_substring_data(
len = 0;
}
- if (offset >= len) {
+ if (offset > len) {
return DOM_INDEX_SIZE_ERR;
}
@@ -210,9 +218,7 @@ dom_exception _dom_characterdata_append_data(struct dom_characterdata *cdata,
return DOM_NO_MODIFICATION_ALLOWED_ERR;
}
- err = dom_string_insert(c->value, data,
- c->value != NULL ? dom_string_length(c->value) : 0,
- &temp);
+ err = dom_string_concat(c->value, data, &temp);
if (err != DOM_NO_ERR) {
return err;
}
@@ -255,7 +261,7 @@ dom_exception _dom_characterdata_insert_data(struct dom_characterdata *cdata,
len = 0;
}
- if (offset >= len) {
+ if (offset > len) {
return DOM_INDEX_SIZE_ERR;
}
@@ -302,7 +308,7 @@ dom_exception _dom_characterdata_delete_data(struct dom_characterdata *cdata,
len = 0;
}
- if (offset >= len) {
+ if (offset > len) {
return DOM_INDEX_SIZE_ERR;
}
@@ -353,7 +359,7 @@ dom_exception _dom_characterdata_replace_data(struct dom_characterdata *cdata,
len = 0;
}
- if (offset >= len) {
+ if (offset > len) {
return DOM_INDEX_SIZE_ERR;
}
@@ -373,3 +379,38 @@ dom_exception _dom_characterdata_replace_data(struct dom_characterdata *cdata,
return DOM_NO_ERR;
}
+
+
+/*----------------------------------------------------------------------*/
+
+/* The protected virtual functions of Node, see core/node.h for details
+ *
+ * @note: the three following API never be called directly from the virtual
+ * functions dispatch mechanism, they are here for the code consistent.
+ */
+void _dom_characterdata_destroy(struct dom_node_internal *node)
+{
+ assert("Should never be here" == NULL);
+ UNUSED(node);
+}
+
+/* The memory allocator of this class */
+dom_exception _dom_characterdata_alloc(struct dom_document *doc,
+ struct dom_node_internal *n, struct dom_node_internal **ret)
+{
+ assert("Should never be here" == NULL);
+ UNUSED(doc);
+ UNUSED(n);
+ UNUSED(ret);
+
+ return DOM_NO_ERR;
+}
+
+/* The copy constructor of this class
+ * The sub-class of characterdata should call this API */
+dom_exception _dom_characterdata_copy(struct dom_node_internal *new,
+ struct dom_node_internal *old)
+{
+ return _dom_node_copy(new, old);
+}
+
diff --git a/src/core/characterdata.h b/src/core/characterdata.h
index 7076988..b5886ea 100644
--- a/src/core/characterdata.h
+++ b/src/core/characterdata.h
@@ -19,15 +19,17 @@ struct dom_characterdata {
struct dom_node_internal base; /**< Base node */
};
-dom_characterdata *dom_characterdata_create(struct dom_document *doc);
-dom_exception dom_characterdata_initialise(struct dom_characterdata *cdata,
+/* The CharacterData is a intermediate node type, so the following function
+ * may never be used */
+dom_characterdata *_dom_characterdata_create(struct dom_document *doc);
+dom_exception _dom_characterdata_initialise(struct dom_characterdata *cdata,
struct dom_document *doc, dom_node_type type,
- struct dom_string *name, struct dom_string *value);
+ struct lwc_string_s *name, struct dom_string *value);
-void dom_characterdata_finalise(struct dom_document *doc,
+void _dom_characterdata_finalise(struct dom_document *doc,
struct dom_characterdata *cdata);
-/* The virtual functions for characterdata */
+/* The virtual functions for dom_characterdata */
dom_exception _dom_characterdata_get_data(struct dom_characterdata *cdata,
struct dom_string **data);
dom_exception _dom_characterdata_set_data(struct dom_characterdata *cdata,
@@ -57,4 +59,21 @@ dom_exception _dom_characterdata_replace_data(struct dom_characterdata *cdata,
_dom_characterdata_delete_data, \
_dom_characterdata_replace_data
+/* Following comes the protected vtable
+ *
+ * Only the _copy function can be used by sub-class of this.
+ */
+void _dom_characterdata_destroy(struct dom_node_internal *node);
+dom_exception _dom_characterdata_alloc(struct dom_document *doc,
+ struct dom_node_internal *n, struct dom_node_internal **ret);
+dom_exception _dom_characterdata_copy(struct dom_node_internal *new,
+ struct dom_node_internal *old);
+
+#define DOM_CHARACTERDATA_PROTECT_VTABLE \
+ _dom_characterdata_destroy, \
+ _dom_characterdata_alloc, \
+ _dom_characterdata_copy
+
+extern struct dom_characterdata_vtable characterdata_vtable;
+
#endif
diff --git a/src/core/comment.c b/src/core/comment.c
index 2e1c323..564bcd8 100644
--- a/src/core/comment.c
+++ b/src/core/comment.c
@@ -3,19 +3,26 @@
* Licensed under the MIT License,
* http://www.opensource.org/licenses/mit-license.php
* Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
*/
#include "core/characterdata.h"
#include "core/comment.h"
#include "core/document.h"
+#include "utils/utils.h"
+
/**
- * A DOM comment node
+ * A DOM Comment node
*/
struct dom_comment {
struct dom_characterdata base; /**< Base node */
};
+static struct dom_node_protect_vtable comment_protect_vtable = {
+ DOM_COMMENT_PROTECT_VTABLE
+};
+
/**
* Create a comment node
*
@@ -30,23 +37,27 @@ struct dom_comment {
*
* The returned node will already be referenced.
*/
-dom_exception dom_comment_create(struct dom_document *doc,
- struct dom_string *name, struct dom_string *value,
+dom_exception _dom_comment_create(struct dom_document *doc,
+ struct lwc_string_s *name, struct dom_string *value,
struct dom_comment **result)
{
struct dom_comment *c;
dom_exception err;
/* Allocate the comment node */
- c = dom_document_alloc(doc, NULL, sizeof(struct dom_comment));
+ c = _dom_document_alloc(doc, NULL, sizeof(struct dom_comment));
if (c == NULL)
return DOM_NO_MEM_ERR;
+ /* Set the virtual table */
+ ((dom_node_internal *) c)->base.vtable = &characterdata_vtable;
+ ((dom_node_internal *) c)->vtable = &comment_protect_vtable;
+
/* And initialise the node */
- err = dom_characterdata_initialise(&c->base, doc, DOM_COMMENT_NODE,
+ err = _dom_characterdata_initialise(&c->base, doc, DOM_COMMENT_NODE,
name, value);
if (err != DOM_NO_ERR) {
- dom_document_alloc(doc, c, 0);
+ _dom_document_alloc(doc, c, 0);
return err;
}
@@ -63,12 +74,50 @@ dom_exception dom_comment_create(struct dom_document *doc,
*
* The contents of ::comment will be destroyed and ::comment will be freed
*/
-void dom_comment_destroy(struct dom_document *doc,
+void _dom_comment_destroy(struct dom_document *doc,
struct dom_comment *comment)
{
/* Finalise base class contents */
- dom_characterdata_finalise(doc, &comment->base);
+ _dom_characterdata_finalise(doc, &comment->base);
/* Free node */
- dom_document_alloc(doc, comment, 0);
+ _dom_document_alloc(doc, comment, 0);
}
+
+
+/*-----------------------------------------------------------------------*/
+/* The protected virtual functions */
+
+/* The virtual destroy function */
+void __dom_comment_destroy(struct dom_node_internal *node)
+{
+ struct dom_document *doc;
+ doc = dom_node_get_owner(node);
+
+ _dom_comment_destroy(doc, (struct dom_comment *) node);
+}
+
+/* The memory allocation function of this class */
+dom_exception _dom_comment_alloc(struct dom_document *doc,
+ struct dom_node_internal *n, struct dom_node_internal **ret)
+{
+ UNUSED(n);
+ dom_comment *c;
+
+ c = _dom_document_alloc(doc, NULL, sizeof(struct dom_comment));
+ if (c == NULL)
+ return DOM_NO_MEM_ERR;
+
+ *ret = (dom_node_internal *) c;
+ dom_node_set_owner(*ret, doc);
+
+ return DOM_NO_ERR;
+}
+
+/* The copy constructor of this class */
+dom_exception _dom_comment_copy(struct dom_node_internal *new,
+ struct dom_node_internal *old)
+{
+ return _dom_characterdata_copy(new, old);
+}
+
diff --git a/src/core/comment.h b/src/core/comment.h
index 38bb448..ef8791f 100644
--- a/src/core/comment.h
+++ b/src/core/comment.h
@@ -9,16 +9,33 @@
#define dom_internal_core_comment_h_
#include <dom/core/exceptions.h>
+#include <dom/core/comment.h>
struct dom_comment;
struct dom_document;
struct dom_string;
+struct lwc_string_s;
-dom_exception dom_comment_create(struct dom_document *doc,
- struct dom_string *name, struct dom_string *value,
+dom_exception _dom_comment_create(struct dom_document *doc,
+ struct lwc_string_s *name, struct dom_string *value,
struct dom_comment **result);
-void dom_comment_destroy(struct dom_document *doc,
+#define _dom_comment_initialise _dom_characterdata_initialise
+#define _dom_comment_finalise _dom_characterdata_finalise
+
+void _dom_comment_destroy(struct dom_document *doc,
struct dom_comment *comment);
+/* Following comes the protected vtable */
+void __dom_comment_destroy(struct dom_node_internal *node);
+dom_exception _dom_comment_alloc(struct dom_document *doc,
+ struct dom_node_internal *n, struct dom_node_internal **ret);
+dom_exception _dom_comment_copy(struct dom_node_internal *new,
+ struct dom_node_internal *old);
+
+#define DOM_COMMENT_PROTECT_VTABLE \
+ __dom_comment_destroy, \
+ _dom_comment_alloc, \
+ _dom_comment_copy
+
#endif
diff --git a/src/core/doc_fragment.c b/src/core/doc_fragment.c
index d9eb272..6b46696 100644
--- a/src/core/doc_fragment.c
+++ b/src/core/doc_fragment.c
@@ -3,13 +3,17 @@
* Licensed under the MIT License,
* http://www.opensource.org/licenses/mit-license.php
* Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
*/
+#include <libwapcaplet/libwapcaplet.h>
+
#include <dom/core/node.h>
#include "core/document.h"
#include "core/doc_fragment.h"
#include "core/node.h"
+#include "utils/utils.h"
/**
* A DOM document fragment
@@ -18,7 +22,13 @@ struct dom_document_fragment {
struct dom_node_internal base; /**< Base node */
};
-void _dom_document_fragment_destroy(struct dom_node_internal *node);
+static struct dom_node_vtable df_vtable = {
+ DOM_NODE_VTABLE
+};
+
+static struct dom_node_protect_vtable df_protect_vtable = {
+ DOM_DF_PROTECT_VTABLE
+};
/**
* Create a document fragment
@@ -34,30 +44,31 @@ void _dom_document_fragment_destroy(struct dom_node_internal *node);
*
* The returned node will already be referenced.
*/
-dom_exception dom_document_fragment_create(struct dom_document *doc,
- struct dom_string *name, struct dom_string *value,
+dom_exception _dom_document_fragment_create(struct dom_document *doc,
+ struct lwc_string_s *name, struct dom_string *value,
struct dom_document_fragment **result)
{
struct dom_document_fragment *f;
dom_exception err;
/* Allocate the comment node */
- f = dom_document_alloc(doc, NULL,
+ f = _dom_document_alloc(doc, NULL,
sizeof(struct dom_document_fragment));
if (f == NULL)
return DOM_NO_MEM_ERR;
+
+ f->base.base.vtable = &df_vtable;
+ f->base.vtable = &df_protect_vtable;
+
/* And initialise the node */
- err = dom_node_initialise(&f->base, doc, DOM_DOCUMENT_FRAGMENT_NODE,
- name, value, NULL, NULL);
+ err = _dom_document_fragment_initialise(&f->base, doc,
+ DOM_DOCUMENT_FRAGMENT_NODE, name, value, NULL, NULL);
if (err != DOM_NO_ERR) {
- dom_document_alloc(doc, f, 0);
+ _dom_document_alloc(doc, f, 0);
return err;
}
- /* Set the virtual function of destroy */
- f->base.destroy = &_dom_document_fragment_destroy;
-
*result = f;
return DOM_NO_ERR;
@@ -71,45 +82,49 @@ dom_exception dom_document_fragment_create(struct dom_document *doc,
*
* The contents of ::frag will be destroyed and ::frag will be freed.
*/
-void dom_document_fragment_destroy(struct dom_document *doc,
+void _dom_document_fragment_destroy(struct dom_document *doc,
struct dom_document_fragment *frag)
{
- struct dom_node_internal *c, *d;
-
- /* Destroy children of this node */
- for (c = frag->base.first_child; c != NULL; c = d) {
- d = c->next;
-
- /* Detach child */
- c->parent = NULL;
-
- if (c->refcnt > 0) {
- /* Something is using this child */
+ /* Finalise base class */
+ _dom_document_fragment_finalise(doc, &frag->base);
- /** \todo add to list of nodes pending deletion */
+ /* Destroy fragment */
+ _dom_document_alloc(doc, frag, 0);
+}
- continue;
- }
+/*-----------------------------------------------------------------------*/
- /* Detach from sibling list */
- c->previous = NULL;
- c->next = NULL;
+/* Overload protected functions */
- dom_node_destroy(c);
- }
+/* The virtual destroy function of this class */
+void _dom_df_destroy(struct dom_node_internal *node)
+{
+ _dom_document_fragment_destroy(node->owner,
+ (struct dom_document_fragment *) node);
+}
- /* Finalise base class */
- dom_node_finalise(doc, &frag->base);
+/* The memory allocator of this class */
+dom_exception _dom_df_alloc(struct dom_document *doc,
+ struct dom_node_internal *n, struct dom_node_internal **ret)
+{
+ UNUSED(n);
+ struct dom_document_fragment *a;
+
+ a = _dom_document_alloc(doc, NULL,
+ sizeof(struct dom_document_fragment));
+ if (a == NULL)
+ return DOM_NO_MEM_ERR;
+
+ *ret = (dom_node_internal *) a;
+ dom_node_set_owner(*ret, doc);
- /* Destroy fragment */
- dom_document_alloc(doc, frag, 0);
+ return DOM_NO_ERR;
}
-void _dom_document_fragment_destroy(struct dom_node_internal *node)
+/* The copy constructor of this class */
+dom_exception _dom_df_copy(struct dom_node_internal *new,
+ struct dom_node_internal *old)
{
- struct dom_document *doc;
- dom_node_get_owner_document(node, &doc);
-
- dom_document_fragment_destroy(doc,
- (struct dom_document_fragment *) node);
+ return _dom_node_copy(new, old);
}
+
diff --git a/src/core/doc_fragment.h b/src/core/doc_fragment.h
index 08e3422..9d3de76 100644
--- a/src/core/doc_fragment.h
+++ b/src/core/doc_fragment.h
@@ -13,12 +13,29 @@
struct dom_document_fragment;
struct dom_document;
struct dom_string;
+struct lwc_string_s;
-dom_exception dom_document_fragment_create(struct dom_document *doc,
- struct dom_string *name, struct dom_string *value,
+dom_exception _dom_document_fragment_create(struct dom_document *doc,
+ struct lwc_string_s *name, struct dom_string *value,
struct dom_document_fragment **result);
-void dom_document_fragment_destroy(struct dom_document *doc,
+void _dom_document_fragment_destroy(struct dom_document *doc,
struct dom_document_fragment *frag);
+#define _dom_document_fragment_initialise _dom_node_initialise
+#define _dom_document_fragment_finalise _dom_node_finalise
+
+
+/* Following comes the protected vtable */
+void _dom_df_destroy(struct dom_node_internal *node);
+dom_exception _dom_df_alloc(struct dom_document *doc,
+ struct dom_node_internal *n, struct dom_node_internal **ret);
+dom_exception _dom_df_copy(struct dom_node_internal *new,
+ struct dom_node_internal *old);
+
+#define DOM_DF_PROTECT_VTABLE \
+ _dom_df_destroy, \
+ _dom_df_alloc, \
+ _dom_df_copy
+
#endif
diff --git a/src/core/document.c b/src/core/document.c
index 355d7f8..7d7e64a 100644
--- a/src/core/document.c
+++ b/src/core/document.c
@@ -3,16 +3,21 @@
* Licensed under the MIT License,
* http://www.opensource.org/licenses/mit-license.php
* Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
*/
-#include <string.h>
+#include <assert.h>
+
+#include <libwapcaplet/libwapcaplet.h>
#include <dom/functypes.h>
#include <dom/bootstrap/implpriv.h>
+#include <dom/core/attr.h>
+#include <dom/core/element.h>
#include <dom/core/document.h>
#include <dom/core/implementation.h>
-#include <dom/core/string.h>
+#include "core/string.h"
#include "core/attr.h"
#include "core/cdatasection.h"
#include "core/comment.h"
@@ -24,6 +29,7 @@
#include "core/nodelist.h"
#include "core/pi.h"
#include "core/text.h"
+#include "utils/validate.h"
#include "utils/namespace.h"
#include "utils/utils.h"
@@ -37,21 +43,6 @@ struct dom_doc_nl {
struct dom_doc_nl *prev; /**< Previous item */
};
-/**
- * Item in list of active namednodemaps
- */
-struct dom_doc_nnm {
- struct dom_namednodemap *map; /**< Named node map */
-
- struct dom_doc_nnm *next; /**< Next map */
- struct dom_doc_nnm *prev; /**< Previous map */
-};
-
-
-/** Interned node name strings, indexed by node type */
-/* Index 0 is unused */
-static struct dom_string *__nodenames_utf8[DOM_NODE_TYPE_COUNT + 1];
-
/* The virtual functions of this dom_document */
static struct dom_document_vtable document_vtable = {
{
@@ -60,84 +51,31 @@ static struct dom_document_vtable document_vtable = {
DOM_DOCUMENT_VTABLE
};
-/**
- * Initialise the document module
- *
- * \param alloc Memory (de)allocation function
- * \param pw Pointer to client-specific private data
- * \return DOM_NO_ERR on success
- */
-dom_exception _dom_document_initialise(dom_alloc alloc, void *pw)
-{
- static struct {
- const char *name;
- size_t len;
- } names_utf8[DOM_NODE_TYPE_COUNT + 1] = {
- { NULL, 0 }, /* Unused */
- { NULL, 0 }, /* Element */
- { NULL, 0 }, /* Attr */
- { "#text", 5 }, /* Text */
- { "#cdata-section", 14 }, /* CDATA section */
- { NULL, 0 }, /* Entity reference */
- { NULL, 0 }, /* Entity */
- { NULL, 0 }, /* Processing instruction */
- { "#comment", 8 }, /* Comment */
- { "#document", 9 }, /* Document */
- { NULL, 0 }, /* Document type */
- { "#document-fragment", 18 }, /* Document fragment */
- { NULL, 0 } /* Notation */
- };
- dom_exception err;
+static struct dom_node_protect_vtable document_protect_vtable = {
+ DOM_DOCUMENT_PROTECT_VTABLE
+};
- /* Initialise interned node names */
- for (int i = 0; i <= DOM_NODE_TYPE_COUNT; i++) {
- if (names_utf8[i].name == NULL) {
- /* Nothing to intern; skip this entry */
- __nodenames_utf8[i] = NULL;
- continue;
- }
- /* Make string */
- err = dom_string_create(alloc, pw,
- (const uint8_t *) names_utf8[i].name,
- names_utf8[i].len, &__nodenames_utf8[i]);
- if (err != DOM_NO_ERR) {
- /* Failed, clean up strings we've created so far */
- for (int j = 0; j < i; j++) {
- if (__nodenames_utf8[j] != NULL) {
- dom_string_unref(__nodenames_utf8[j]);
- }
- }
- return err;
- }
- }
+/*----------------------------------------------------------------------*/
- return DOM_NO_ERR;
-}
+/* Internally used helper functions */
+static dom_exception dom_document_dup_node(dom_document *doc,
+ struct dom_node *node, bool deep, struct dom_node **result,
+ dom_node_operation opt);
-/**
- * Finalise the document module
- *
- * \return DOM_NO_ERR.
- */
-dom_exception _dom_document_finalise(void)
-{
- for (int i = 0; i <= DOM_NODE_TYPE_COUNT; i++) {
- if (__nodenames_utf8[i] != NULL) {
- dom_string_unref(__nodenames_utf8[i]);
- }
- }
- return DOM_NO_ERR;
-}
+/*----------------------------------------------------------------------*/
+
+/* The constructors and destructors */
/**
* Create a Document
*
- * \param impl The DOM implementation owning the document
- * \param alloc Memory (de)allocation function
- * \param pw Pointer to client-specific private data
- * \param doc Pointer to location to receive created document
+ * \param impl The DOM implementation owning the document
+ * \param alloc Memory (de)allocation function
+ * \param pw Pointer to client-specific private data
+ * \param doc Pointer to location to receive created document
+ * \param ctx The intern string context of this document
* \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion.
*
* ::impl will have its reference count increased.
@@ -145,7 +83,8 @@ dom_exception _dom_document_finalise(void)
* The returned document will already be referenced.
*/
dom_exception dom_document_create(struct dom_implementation *impl,
- dom_alloc alloc, void *pw, struct dom_document **doc)
+ dom_alloc alloc, void *pw, struct lwc_context_s *ctx,
+ struct dom_document **doc)
{
struct dom_document *d;
dom_exception err;
@@ -155,103 +94,107 @@ dom_exception dom_document_create(struct dom_implementation *impl,
if (d == NULL)
return DOM_NO_MEM_ERR;
- /* Set up document allocation context - must be first */
- d->alloc = alloc;
- d->pw = pw;
-
/* Initialise the virtual table */
d->base.base.vtable = &document_vtable;
- d->base.destroy = &dom_document_destroy;
+ d->base.vtable = &document_protect_vtable;
/* Initialise base class -- the Document has no parent, so
* destruction will be attempted as soon as its reference count
* reaches zero. Documents own themselves (this simplifies the
* rest of the code, as it doesn't need to special case Documents)
*/
- err = dom_node_initialise(&d->base, d, DOM_DOCUMENT_NODE,
- NULL, NULL, NULL, NULL);
+ err = _dom_document_initialise(d, impl, alloc, pw, ctx);
if (err != DOM_NO_ERR) {
/* Clean up document */
alloc(d, 0, pw);
return err;
}
- /* Initialise remaining type-specific data */
- if (impl != NULL)
- dom_implementation_ref(impl);
- d->impl = impl;
-
- d->nodelists = NULL;
- d->maps = NULL;
-
- d->nodenames = __nodenames_utf8;
-
*doc = d;
return DOM_NO_ERR;
}
-/**
- * Destroy a document
- *
- * \param doc The document to destroy, which is passed in as a
- *
- * dom_node_internl
- *
- * The contents of ::doc will be destroyed and ::doc will be freed.
- */
-void dom_document_destroy(struct dom_node_internal *dnode)
+/* Initialise the document */
+dom_exception _dom_document_initialise(struct dom_document *doc,
+ struct dom_implementation *impl, dom_alloc alloc, void *pw,
+ struct lwc_context_s *ctx)
{
- struct dom_document *doc = (struct dom_document *) dnode;
- struct dom_node_internal *c, *d;
+ assert(ctx != NULL);
+ assert(alloc != NULL);
+ assert(impl != NULL);
- /* Destroy children of this node */
- for (c = doc->base.first_child; c != NULL; c = d) {
- d = c->next;
+ dom_exception err;
+ lwc_string *name;
+ lwc_error lerr;
+
+ lerr = lwc_context_intern(ctx, "#document", SLEN("#document"), &name);
+ if (lerr != lwc_error_ok)
+ return _dom_exception_from_lwc_error(lerr);
- /* Detach child */
- c->parent = NULL;
+ dom_implementation_ref(impl);
+ doc->impl = impl;
- if (c->refcnt > 0) {
- /* Something is using this child */
+ doc->nodelists = NULL;
- /** \todo add to list of nodes pending deletion */
+ /* Set up document allocation context - must be first */
+ doc->alloc = alloc;
+ doc->pw = pw;
+ doc->context = lwc_context_ref(ctx);
- continue;
- }
+ err = _dom_node_initialise(&doc->base, doc, DOM_DOCUMENT_NODE,
+ name, NULL, NULL, NULL);
+ lwc_context_string_unref(ctx, name);
- /* Detach from sibling list */
- c->previous = NULL;
- c->next = NULL;
+ list_init(&doc->pending_nodes);
- dom_node_destroy(c);
- }
+ doc->id_name = NULL;
- /** \todo Ensure list of nodes pending deletion is empty. If not,
+ return err;
+}
+
+
+/* Finalise the document */
+bool _dom_document_finalise(struct dom_document *doc)
+{
+ /* Finalise base class, delete the tree in force */
+ _dom_node_finalise(doc, &doc->base);
+
+ /* Now, the first_child and last_child should be null */
+ doc->base.first_child = NULL;
+ doc->base.last_child = NULL;
+
+ /* Ensure list of nodes pending deletion is empty. If not,
* then we can't yet destroy the document (its destruction will
* have to wait until the pending nodes are destroyed) */
+ if (doc->pending_nodes.next != &doc->pending_nodes)
+ return false;
/* Ok, the document tree is empty, as is the list of nodes pending
* deletion. Therefore, it is safe to destroy the document. */
-
if (doc->impl != NULL)
dom_implementation_unref(doc->impl);
doc->impl = NULL;
- /* This is paranoia -- if there are any remaining nodelists or
- * namednodemaps, then the document's reference count will be
+ /* This is paranoia -- if there are any remaining nodelists,
+ * then the document's reference count will be
* non-zero as these data structures reference the document because
* they are held by the client. */
doc->nodelists = NULL;
- doc->maps = NULL;
- /* Finalise base class */
- dom_node_finalise(doc, &doc->base);
+ if (doc->id_name != NULL)
+ lwc_context_string_unref(doc->context, doc->id_name);
+ lwc_context_unref(doc->context);
- /* Free document */
- doc->alloc(doc, 0, doc->pw);
+ return true;
}
+
+
+/*----------------------------------------------------------------------*/
+
+/* Public virtual functions */
+
/**
* Retrieve the doctype of a document
*
@@ -319,7 +262,7 @@ dom_exception _dom_document_get_document_element(struct dom_document *doc,
{
struct dom_node_internal *root;
- /* Find first element node in child list */
+ /* Find the first element node in child list */
for (root = doc->base.first_child; root != NULL; root = root->next) {
if (root->type == DOM_ELEMENT_NODE)
break;
@@ -351,7 +294,21 @@ dom_exception _dom_document_get_document_element(struct dom_document *doc,
dom_exception _dom_document_create_element(struct dom_document *doc,
struct dom_string *tag_name, struct dom_element **result)
{
- return dom_element_create(doc, tag_name, NULL, NULL, result);
+ lwc_string *name;
+ dom_exception err;
+
+ if (_dom_validate_name(tag_name) == false)
+ return DOM_INVALID_CHARACTER_ERR;
+
+ assert(doc->context != NULL);
+ err = _dom_string_intern(tag_name, doc->context, &name);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ err = _dom_element_create(doc, name, NULL, NULL, result);
+ lwc_context_string_unref(doc->context, name);
+
+ return err;
}
/**
@@ -368,9 +325,21 @@ dom_exception _dom_document_create_element(struct dom_document *doc,
dom_exception _dom_document_create_document_fragment(struct dom_document *doc,
struct dom_document_fragment **result)
{
- return dom_document_fragment_create(doc,
- doc->nodenames[DOM_DOCUMENT_FRAGMENT_NODE],
- NULL, result);
+ lwc_string *name;
+ dom_exception err;
+ lwc_error lerr;
+
+ assert(doc->context != NULL);
+
+ lerr = lwc_context_intern(doc->context, "#document-fragment",
+ SLEN("#document-fragment"), &name);
+ if (lerr != lwc_error_ok)
+ return _dom_exception_from_lwc_error(lerr);
+
+ err = _dom_document_fragment_create(doc, name, NULL, result);
+ lwc_context_string_unref(doc->context, name);
+
+ return err;
}
/**
@@ -388,8 +357,20 @@ dom_exception _dom_document_create_document_fragment(struct dom_document *doc,
dom_exception _dom_document_create_text_node(struct dom_document *doc,
struct dom_string *data, struct dom_text **result)
{
- return dom_text_create(doc, doc->nodenames[DOM_TEXT_NODE],
- data, result);
+ lwc_string *name;
+ dom_exception err;
+ lwc_error lerr;
+
+ assert(doc->context != NULL);
+
+ lerr = lwc_context_intern(doc->context, "#text", SLEN("#text"), &name);
+ if (lerr != lwc_error_ok)
+ return _dom_exception_from_lwc_error(lerr);
+
+ err = _dom_text_create(doc, name, data, result);
+ lwc_context_string_unref(doc->context, name);
+
+ return err;
}
/**
@@ -407,8 +388,21 @@ dom_exception _dom_document_create_text_node(struct dom_document *doc,
dom_exception _dom_document_create_comment(struct dom_document *doc,
struct dom_string *data, struct dom_comment **result)
{
- return dom_comment_create(doc, doc->nodenames[DOM_COMMENT_NODE],
- data, result);
+ lwc_string *name;
+ dom_exception err;
+ lwc_error lerr;
+
+ assert(doc->context != NULL);
+
+ lerr = lwc_context_intern(doc->context, "#comment", SLEN("#comment"),
+ &name);
+ if (lerr != lwc_error_ok)
+ return _dom_exception_from_lwc_error(lerr);
+
+ err = _dom_comment_create(doc, name, data, result);
+ lwc_context_string_unref(doc->context, name);
+
+ return err;
}
/**
@@ -427,9 +421,21 @@ dom_exception _dom_document_create_comment(struct dom_document *doc,
dom_exception _dom_document_create_cdata_section(struct dom_document *doc,
struct dom_string *data, struct dom_cdata_section **result)
{
- return dom_cdata_section_create(doc,
- doc->nodenames[DOM_CDATA_SECTION_NODE],
- data, result);
+ lwc_string *name;
+ dom_exception err;
+ lwc_error lerr;
+
+ assert(doc->context != NULL);
+
+ lerr = lwc_context_intern(doc->context, "#cdata-section",
+ SLEN("#cdata-section"), &name);
+ if (lerr != lwc_error_ok)
+ return _dom_exception_from_lwc_error(lerr);
+
+ err = _dom_cdata_section_create(doc, name, data, result);
+ lwc_context_string_unref(doc->context, name);
+
+ return err;
}
/**
@@ -452,7 +458,21 @@ dom_exception _dom_document_create_processing_instruction(
struct dom_string *data,
struct dom_processing_instruction **result)
{
- return dom_processing_instruction_create(doc, target, data, result);
+ lwc_string *name;
+ dom_exception err;
+
+ if (_dom_validate_name(target) == false)
+ return DOM_INVALID_CHARACTER_ERR;
+
+ assert(doc->context != NULL);
+ err = _dom_string_intern(target, doc->context, &name);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ err = _dom_processing_instruction_create(doc, name, data, result);
+ lwc_context_string_unref(doc->context, name);
+
+ return err;
}
/**
@@ -471,7 +491,20 @@ dom_exception _dom_document_create_processing_instruction(
dom_exception _dom_document_create_attribute(struct dom_document *doc,
struct dom_string *name, struct dom_attr **result)
{
- return dom_attr_create(doc, name, NULL, NULL, result);
+ lwc_string *n;
+ dom_exception err;
+
+ if (_dom_validate_name(name) == false)
+ return DOM_INVALID_CHARACTER_ERR;
+
+ assert(doc->context != NULL);
+ err = _dom_string_intern(name, doc->context, &n);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ err = _dom_attr_create(doc, n, NULL, NULL, true, result);
+ lwc_context_string_unref(doc->context, n);
+ return err;
}
/**
@@ -492,7 +525,20 @@ dom_exception _dom_document_create_entity_reference(struct dom_document *doc,
struct dom_string *name,
struct dom_entity_reference **result)
{
- return dom_entity_reference_create(doc, name, NULL, result);
+ lwc_string *n;
+ dom_exception err;
+
+ if (_dom_validate_name(name) == false)
+ return DOM_INVALID_CHARACTER_ERR;
+
+ assert(doc->context != NULL);
+ err = _dom_string_intern(name, doc->context, &n);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ err = _dom_entity_reference_create(doc, n, NULL, result);
+ lwc_context_string_unref(doc->context, n);
+ return err;
}
/**
@@ -510,8 +556,20 @@ dom_exception _dom_document_create_entity_reference(struct dom_document *doc,
dom_exception _dom_document_get_elements_by_tag_name(struct dom_document *doc,
struct dom_string *tagname, struct dom_nodelist **result)
{
- return dom_document_get_nodelist(doc, (struct dom_node_internal *) doc,
- tagname, NULL, NULL, result);
+ lwc_string *name;
+ dom_exception err;
+
+ assert(doc->context != NULL);
+ err = _dom_string_intern(tagname, doc->context, &name);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ err = _dom_document_get_nodelist(doc, DOM_NODELIST_BY_NAME,
+ (struct dom_node_internal *) doc, name, NULL, NULL,
+ result);
+ lwc_context_string_unref(doc->context, name);
+
+ return err;
}
/**
@@ -532,12 +590,10 @@ dom_exception _dom_document_get_elements_by_tag_name(struct dom_document *doc,
dom_exception _dom_document_import_node(struct dom_document *doc,
struct dom_node *node, bool deep, struct dom_node **result)
{
- UNUSED(doc);
- UNUSED(node);
- UNUSED(deep);
- UNUSED(result);
+ /* TODO: The DOM_INVALID_CHARACTER_ERR exception */
- return DOM_NOT_SUPPORTED_ERR;
+ return dom_document_dup_node(doc, node, deep, result,
+ DOM_NODE_IMPORTED);
}
/**
@@ -575,7 +631,8 @@ dom_exception _dom_document_create_element_ns(struct dom_document *doc,
struct dom_string *prefix, *localname;
dom_exception err;
- /** \todo ensure document supports XML feature */
+ if (_dom_validate_name(qname) == false)
+ return DOM_INVALID_CHARACTER_ERR;
/* Validate qname */
err = _dom_namespace_validate_qname(qname, namespace);
@@ -589,13 +646,57 @@ dom_exception _dom_document_create_element_ns(struct dom_document *doc,
return err;
}
+ /* Get the interned string from the dom_string */
+ assert(doc->context != NULL);
+ lwc_string *l = NULL, *n = NULL, *p = NULL;
+ if (localname != NULL) {
+ err = _dom_string_intern(localname, doc->context, &l);
+ if (err != DOM_NO_ERR) {
+ dom_string_unref(localname);
+ if (prefix != NULL)
+ dom_string_unref(prefix);
+
+ return err;
+ }
+ }
+ if (namespace != NULL) {
+ err = _dom_string_intern(namespace, doc->context, &n);
+ if (err != DOM_NO_ERR) {
+ lwc_context_string_unref(doc->context, l);
+ dom_string_unref(localname);
+ if (prefix != NULL)
+ dom_string_unref(prefix);
+
+ return err;
+ }
+ }
+ if (prefix != NULL) {
+ err = _dom_string_intern(prefix, doc->context, &p);
+ if (err != DOM_NO_ERR) {
+ lwc_context_string_unref(doc->context, l);
+ lwc_context_string_unref(doc->context, n);
+ dom_string_unref(localname);
+ if (prefix != NULL)
+ dom_string_unref(prefix);
+
+ return err;
+ }
+ }
+
/* Attempt to create element */
- err = dom_element_create(doc, localname, namespace, prefix, result);
+ err = _dom_element_create(doc, l, n, p, result);
/* Tidy up */
- dom_string_unref(localname);
+ if (localname != NULL) {
+ dom_string_unref(localname);
+ lwc_context_string_unref(doc->context, l);
+ }
if (prefix != NULL) {
dom_string_unref(prefix);
+ lwc_context_string_unref(doc->context, p);
+ }
+ if (namespace != NULL) {
+ lwc_context_string_unref(doc->context, n);
}
return err;
@@ -636,7 +737,8 @@ dom_exception _dom_document_create_attribute_ns(struct dom_document *doc,
struct dom_string *prefix, *localname;
dom_exception err;
- /** \todo ensure document supports XML feature */
+ if (_dom_validate_name(qname) == false)
+ return DOM_INVALID_CHARACTER_ERR;
/* Validate qname */
err = _dom_namespace_validate_qname(qname, namespace);
@@ -650,13 +752,56 @@ dom_exception _dom_document_create_attribute_ns(struct dom_document *doc,
return err;
}
+ /* Get the interned string from the dom_string */
+ assert(doc->context != NULL);
+ lwc_string *l = NULL, *n = NULL, *p = NULL;
+ if (localname != NULL) {
+ err = _dom_string_intern(localname, doc->context, &l);
+ if (err != DOM_NO_ERR) {
+ dom_string_unref(localname);
+ if (prefix != NULL)
+ dom_string_unref(prefix);
+
+ return err;
+ }
+ }
+ if (namespace != NULL) {
+ err = _dom_string_intern(namespace, doc->context, &n);
+ if (err != DOM_NO_ERR) {
+ lwc_context_string_unref(doc->context, l);
+ dom_string_unref(localname);
+ if (prefix != NULL)
+ dom_string_unref(prefix);
+
+ return err;
+ }
+ }
+ if (prefix != NULL) {
+ err = _dom_string_intern(prefix, doc->context, &p);
+ if (err != DOM_NO_ERR) {
+ lwc_context_string_unref(doc->context, l);
+ lwc_context_string_unref(doc->context, n);
+ dom_string_unref(localname);
+ if (prefix != NULL)
+ dom_string_unref(prefix);
+
+ return err;
+ }
+ }
/* Attempt to create attribute */
- err = dom_attr_create(doc, localname, namespace, prefix, result);
+ err = _dom_attr_create(doc, l, n, p, true, result);
/* Tidy up */
- dom_string_unref(localname);
+ if (localname != NULL) {
+ dom_string_unref(localname);
+ lwc_context_string_unref(doc->context, l);
+ }
if (prefix != NULL) {
dom_string_unref(prefix);
+ lwc_context_string_unref(doc->context, p);
+ }
+ if (namespace != NULL) {
+ lwc_context_string_unref(doc->context, n);
}
return err;
@@ -669,7 +814,7 @@ dom_exception _dom_document_create_attribute_ns(struct dom_document *doc,
* \param namespace The namespace URI
* \param localname The local name
* \param result Pointer to location to receive result
- * \return DOM_NO_ERR.
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
*
* The returned list will have its reference count increased. It is
* the responsibility of the caller to unref the list once it has
@@ -679,8 +824,33 @@ dom_exception _dom_document_get_elements_by_tag_name_ns(
struct dom_document *doc, struct dom_string *namespace,
struct dom_string *localname, struct dom_nodelist **result)
{
- return dom_document_get_nodelist(doc, (struct dom_node_internal *) doc,
- NULL, namespace, localname, result);
+ dom_exception err;
+ lwc_string *l = NULL, *n = NULL;
+
+ /* Get the interned string from the dom_string */
+ assert(doc->context != NULL);
+ if (localname != NULL) {
+ err = _dom_string_intern(localname, doc->context, &l);
+ if (err != DOM_NO_ERR)
+ return err;
+ }
+ if (namespace != NULL) {
+ err = _dom_string_intern(namespace, doc->context, &n);
+ if (err != DOM_NO_ERR) {
+ lwc_context_string_unref(doc->context, l);
+ return err;
+ }
+ }
+
+ err = _dom_document_get_nodelist(doc, DOM_NODELIST_BY_NAMESPACE,
+ (struct dom_node_internal *) doc, NULL, n, l, result);
+
+ if (l != NULL)
+ lwc_context_string_unref(doc->context, l);
+ if (n != NULL)
+ lwc_context_string_unref(doc->context, n);
+
+ return err;
}
/**
@@ -689,7 +859,7 @@ dom_exception _dom_document_get_elements_by_tag_name_ns(
* \param doc The document to search in
* \param id The ID to search for
* \param result Pointer to location to receive result
- * \return DOM_NO_ERR.
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
*
* The returned node will have its reference count increased. It is
* the responsibility of the caller to unref the node once it has
@@ -698,11 +868,25 @@ dom_exception _dom_document_get_elements_by_tag_name_ns(
dom_exception _dom_document_get_element_by_id(struct dom_document *doc,
struct dom_string *id, struct dom_element **result)
{
- UNUSED(doc);
- UNUSED(id);
- UNUSED(result);
+ lwc_string *i;
+ dom_node_internal *root;
+ dom_exception err;
- return DOM_NOT_SUPPORTED_ERR;
+ *result = NULL;
+
+ assert(doc->context != NULL);
+ err = _dom_string_intern(id, doc->context, &i);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ err = dom_document_get_document_element(doc, (void *) &root);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ err = _dom_find_element_by_id(root, i, result);
+ dom_node_unref(root);
+
+ return err;
}
/**
@@ -710,7 +894,7 @@ dom_exception _dom_document_get_element_by_id(struct dom_document *doc,
*
* \param doc The document to query
* \param result Pointer to location to receive result
- * \return DOM_NO_ERR.
+ * \return DOM_NOT_SUPPORTED_ERR, we don't support this API now.
*
* The returned string will have its reference count increased. It is
* the responsibility of the caller to unref the string once it has
@@ -730,7 +914,7 @@ dom_exception _dom_document_get_input_encoding(struct dom_document *doc,
*
* \param doc The document to query
* \param result Pointer to location to receive result
- * \return DOM_NO_ERR.
+ * \return DOM_NOT_SUPPORTED_ERR, we don't support this API now.
*
* The returned string will have its reference count increased. It is
* the responsibility of the caller to unref the string once it has
@@ -750,7 +934,7 @@ dom_exception _dom_document_get_xml_encoding(struct dom_document *doc,
*
* \param doc The document to query
* \param result Pointer to location to receive result
- * \return DOM_NO_ERR.
+ * \return DOM_NOT_SUPPORTED_ERR, we don't support this API now.
*/
dom_exception _dom_document_get_xml_standalone(struct dom_document *doc,
bool *result)
@@ -769,6 +953,9 @@ dom_exception _dom_document_get_xml_standalone(struct dom_document *doc,
* \return DOM_NO_ERR on success,
* DOM_NOT_SUPPORTED_ERR if the document does not support the "XML"
* feature.
+ *
+ * We don't support this API now, so the return value is always
+ * DOM_NOT_SUPPORTED_ERR.
*/
dom_exception _dom_document_set_xml_standalone(struct dom_document *doc,
bool standalone)
@@ -784,11 +971,14 @@ dom_exception _dom_document_set_xml_standalone(struct dom_document *doc,
*
* \param doc The document to query
* \param result Pointer to location to receive result
- * \return DOM_NO_ERR.
+ * \return DOM_NO_ERR
*
* The returned string will have its reference count increased. It is
* the responsibility of the caller to unref the string once it has
* finished with it.
+ *
+ * We don't support this API now, so the return value is always
+ * DOM_NOT_SUPPORTED_ERR.
*/
dom_exception _dom_document_get_xml_version(struct dom_document *doc,
struct dom_string **result)
@@ -807,6 +997,9 @@ dom_exception _dom_document_get_xml_version(struct dom_document *doc,
* \return DOM_NO_ERR on success,
* DOM_NOT_SUPPORTED_ERR if the document does not support the "XML"
* feature.
+ *
+ * We don't support this API now, so the return value is always
+ * DOM_NOT_SUPPORTED_ERR.
*/
dom_exception _dom_document_set_xml_version(struct dom_document *doc,
struct dom_string *version)
@@ -822,7 +1015,7 @@ dom_exception _dom_document_set_xml_version(struct dom_document *doc,
*
* \param doc The document to query
* \param result Pointer to location to receive result
- * \return DOM_NO_ERR.
+ * \return DOM_NOT_SUPPORTED_ERR, we don't support this API now.
*/
dom_exception _dom_document_get_strict_error_checking(
struct dom_document *doc, bool *result)
@@ -838,7 +1031,7 @@ dom_exception _dom_document_get_strict_error_checking(
*
* \param doc The document to query
* \param strict Whether to use strict error checking
- * \return DOM_NO_ERR.
+ * \return DOM_NOT_SUPPORTED_ERR, we don't support this API now.
*/
dom_exception _dom_document_set_strict_error_checking(
struct dom_document *doc, bool strict)
@@ -863,10 +1056,10 @@ dom_exception _dom_document_set_strict_error_checking(
dom_exception _dom_document_get_uri(struct dom_document *doc,
struct dom_string **result)
{
- UNUSED(doc);
- UNUSED(result);
+ dom_string_ref(doc->uri);
+ *result = doc->uri;
- return DOM_NOT_SUPPORTED_ERR;
+ return DOM_NO_ERR;
}
/**
@@ -883,10 +1076,11 @@ dom_exception _dom_document_get_uri(struct dom_document *doc,
dom_exception _dom_document_set_uri(struct dom_document *doc,
struct dom_string *uri)
{
- UNUSED(doc);
- UNUSED(uri);
+ dom_string_unref(doc->uri);
+ dom_string_ref(uri);
+ doc->uri = uri;
- return DOM_NOT_SUPPORTED_ERR;
+ return DOM_NO_ERR;
}
/**
@@ -903,15 +1097,62 @@ dom_exception _dom_document_set_uri(struct dom_document *doc,
* The returned node will have its reference count increased. It is
* the responsibility of the caller to unref the node once it has
* finished with it.
+ *
+ * @note: The spec said adoptNode may be light weight than the importNode
+ * because the former need no Node creation. But in our implementation
+ * this can't be ensured. Both adoptNode and importNode create new
+ * nodes using the importing/adopting document's resource manager. So,
+ * generally, the adoptNode and importNode call the same function
+ * dom_document_dup_node.
*/
dom_exception _dom_document_adopt_node(struct dom_document *doc,
struct dom_node *node, struct dom_node **result)
{
- UNUSED(doc);
- UNUSED(node);
- UNUSED(result);
+ dom_exception err;
+ dom_node_internal *n = (dom_node_internal *) node;
+
+ *result = NULL;
- return DOM_NOT_SUPPORTED_ERR;
+ if (n->type == DOM_DOCUMENT_NODE ||
+ n->type == DOM_DOCUMENT_TYPE_NODE) {
+ return DOM_NOT_SUPPORTED_ERR;
+ }
+
+ if (n->type == DOM_ENTITY_NODE ||
+ n->type == DOM_NOTATION_NODE ||
+ n->type == DOM_PROCESSING_INSTRUCTION_NODE ||
+ n->type == DOM_TEXT_NODE ||
+ n->type == DOM_CDATA_SECTION_NODE ||
+ n->type == DOM_COMMENT_NODE) {
+ *result = NULL;
+ return DOM_NO_ERR;
+ }
+
+ /* Support XML when necessary */
+ if (n->type == DOM_ENTITY_REFERENCE_NODE) {
+ return DOM_NOT_SUPPORTED_ERR;
+ }
+
+ err = dom_document_dup_node(doc, node, true, result, DOM_NODE_ADOPTED);
+ if (err != DOM_NO_ERR) {
+ *result = NULL;
+ return err;
+ }
+
+ dom_node_internal *parent = n->parent;
+ dom_node_internal *tmp;
+ if (parent != NULL) {
+ err = dom_node_remove_child(parent, node, (void *) &tmp);
+ if (err != DOM_NO_ERR) {
+ dom_node_unref(*result);
+ *result = NULL;
+ return err;
+ }
+ }
+
+ dom_node_unref(tmp);
+
+ return DOM_NO_ERR;
}
/**
@@ -919,7 +1160,7 @@ dom_exception _dom_document_adopt_node(struct dom_document *doc,
*
* \param doc The document to query
* \param result Pointer to location to receive result
- * \return DOM_NO_ERR.
+ * \return DOM_NOT_SUPPORTED_ERR, we don't support this API now.
*
* The returned object will have its reference count increased. It is
* the responsibility of the caller to unref the object once it has
@@ -938,7 +1179,7 @@ dom_exception _dom_document_get_dom_config(struct dom_document *doc,
* Normalize a document
*
* \param doc The document to normalize
- * \return DOM_NO_ERR.
+ * \return DOM_NOT_SUPPORTED_ERR, we don't support this API now.
*/
dom_exception _dom_document_normalize(struct dom_document *doc)
{
@@ -977,6 +1218,9 @@ dom_exception _dom_document_normalize(struct dom_document *doc)
* The returned node will have its reference count increased. It is
* the responsibility of the caller to unref the node once it has
* finished with it.
+ *
+ * We don't support this API now, so the return value is always
+ * DOM_NOT_SUPPORTED_ERR.
*/
dom_exception _dom_document_rename_node(struct dom_document *doc,
struct dom_node *node,
@@ -992,6 +1236,51 @@ dom_exception _dom_document_rename_node(struct dom_document *doc,
return DOM_NOT_SUPPORTED_ERR;
}
+/*-----------------------------------------------------------------------*/
+
+/* Overload protectd virtual functions */
+
+/* The virtual destroy function of this class */
+void _dom_document_destroy(struct dom_node_internal *node)
+{
+ struct dom_document *doc = (struct dom_document *) node;
+
+ if (_dom_document_finalise(doc) == true) {
+ doc->alloc(doc, 0, doc->pw);
+ }
+}
+
+/* The memory allocation function of this class */
+dom_exception __dom_document_alloc(struct dom_document *doc,
+ struct dom_node_internal *n, struct dom_node_internal **ret)
+{
+ UNUSED(n);
+ struct dom_document *a;
+
+ a = _dom_document_alloc(doc, NULL, sizeof(struct dom_document));
+ if (a == NULL)
+ return DOM_NO_MEM_ERR;
+
+ *ret = (dom_node_internal *) a;
+ dom_node_set_owner(*ret, doc);
+
+ return DOM_NO_ERR;
+}
+
+/* The copy constructor function of this class */
+dom_exception _dom_document_copy(struct dom_node_internal *new,
+ struct dom_node_internal *old)
+{
+ UNUSED(new);
+ UNUSED(old);
+
+ return DOM_NOT_SUPPORTED_ERR;
+}
+
+
+/* ----------------------------------------------------------------------- */
+
+/* Helper functions */
/**
* Create a DOM string, using a document's allocation context
*
@@ -1007,15 +1296,96 @@ dom_exception _dom_document_rename_node(struct dom_document *doc,
* The string of characters passed in will be copied for use by the
* returned DOM string.
*/
-dom_exception dom_document_create_string(struct dom_document *doc,
+dom_exception _dom_document_create_string(struct dom_document *doc,
const uint8_t *data, size_t len, struct dom_string **result)
{
return dom_string_create(doc->alloc, doc->pw, data, len, result);
}
-/* */
-/* ----------------------------------------------------------------------- */
-/* */
+/*
+ * Create a lwc_string
+ *
+ * \param doc The document object
+ * \param data The raw string data
+ * \param len The raw string length
+ * \param result The resturned lwc_string
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ */
+dom_exception _dom_document_create_lwcstring(struct dom_document *doc,
+ const uint8_t *data, size_t len, struct lwc_string_s **result)
+{
+ lwc_error lerr;
+
+ assert(doc->context != NULL);
+
+ lerr = lwc_context_intern(doc->context, (const char *) data, len,
+ result);
+
+ return _dom_exception_from_lwc_error(lerr);
+}
+
+/* Simple accessor for lwc_context of this document */
+struct lwc_context_s *_dom_document_get_intern_context(
+ struct dom_document *doc)
+{
+ return doc->context;
+}
+
+/* Get the resource manager from the document */
+void _dom_document_get_resource_mgr(
+ struct dom_document *doc, struct dom_resource_mgr *rm)
+{
+ rm->alloc = doc->alloc;
+ rm->pw = doc->pw;
+ rm->ctx = doc->context;
+}
+
+/* Simple accessor for allocator data for this document */
+void _dom_document_get_allocator(struct dom_document *doc, dom_alloc *al,
+ void **pw)
+{
+ *al = doc->alloc;
+ *pw = doc->pw;
+}
+/*
+ * Create a dom_string from a lwc_string.
+ *
+ * \param doc The document object
+ * \param str The lwc_string object
+ * \param result The retured dom_string
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ */
+dom_exception _dom_document_create_string_from_lwcstring(
+ struct dom_document *doc, struct lwc_string_s *str,
+ struct dom_string **result)
+{
+ assert(doc->context != NULL);
+
+ return _dom_string_create_from_lwcstring(doc->alloc, doc->pw,
+ doc->context, str, result);
+}
+
+/**
+ * Create a hash_table
+ *
+ * \param doc The dom_document
+ * \param chains The number of chains
+ * \param f The hash function
+ * \param ht The returned hash_table
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ */
+dom_exception _dom_document_create_hashtable(struct dom_document *doc,
+ size_t chains, dom_hash_func f, struct dom_hash_table **ht)
+{
+ struct dom_hash_table *ret;
+
+ ret = _dom_hash_create(chains, f, doc->alloc, doc->pw);
+ if (ret == NULL)
+ return DOM_NO_MEM_ERR;
+
+ *ht = ret;
+ return DOM_NO_ERR;
+}
/**
* (De)allocate memory with a document's context
@@ -1028,7 +1398,7 @@ dom_exception dom_document_create_string(struct dom_document *doc,
* This call (modulo ::doc) has the same semantics as realloc().
* It is a thin veneer over the client-provided allocation function.
*/
-void *dom_document_alloc(struct dom_document *doc, void *ptr, size_t size)
+void *_dom_document_alloc(struct dom_document *doc, void *ptr, size_t size)
{
return doc->alloc(ptr, size, doc->pw);
}
@@ -1037,6 +1407,7 @@ void *dom_document_alloc(struct dom_document *doc, void *ptr, size_t size)
* Get a nodelist, creating one if necessary
*
* \param doc The document to get a nodelist for
+ * \param type The type of the NodeList
* \param root Root node of subtree that list applies to
* \param tagname Name of nodes in list (or NULL)
* \param namespace Namespace part of nodes in list (or NULL)
@@ -1048,16 +1419,16 @@ void *dom_document_alloc(struct dom_document *doc, void *ptr, size_t size)
* the responsibility of the caller to unref the list once it has
* finished with it.
*/
-dom_exception dom_document_get_nodelist(struct dom_document *doc,
- struct dom_node_internal *root, struct dom_string *tagname,
- struct dom_string *namespace, struct dom_string *localname,
- struct dom_nodelist **list)
+dom_exception _dom_document_get_nodelist(struct dom_document *doc,
+ nodelist_type type, struct dom_node_internal *root,
+ struct lwc_string_s *tagname, struct lwc_string_s *namespace,
+ struct lwc_string_s *localname, struct dom_nodelist **list)
{
struct dom_doc_nl *l;
dom_exception err;
for (l = doc->nodelists; l; l = l->next) {
- if (dom_nodelist_match(l->list, root, tagname,
+ if (_dom_nodelist_match(l->list, type, root, tagname,
namespace, localname))
break;
}
@@ -1074,7 +1445,7 @@ dom_exception dom_document_get_nodelist(struct dom_document *doc,
return DOM_NO_MEM_ERR;
/* Create nodelist */
- err = dom_nodelist_create(doc, root, tagname, namespace,
+ err = _dom_nodelist_create(doc, type, root, tagname, namespace,
localname, &l->list);
if (err != DOM_NO_ERR) {
doc->alloc(l, 0, doc->pw);
@@ -1093,7 +1464,7 @@ dom_exception dom_document_get_nodelist(struct dom_document *doc,
* If it did, the nodelist's reference count would never reach zero,
* and the list would remain indefinitely. This is not a problem as
* the list notifies the document of its destruction via
- * dom_document_remove_nodelist. */
+ * _dom_document_remove_nodelist. */
*list = l->list;
@@ -1106,7 +1477,7 @@ dom_exception dom_document_get_nodelist(struct dom_document *doc,
* \param doc The document to remove the list from
* \param list The list to remove
*/
-void dom_document_remove_nodelist(struct dom_document *doc,
+void _dom_document_remove_nodelist(struct dom_document *doc,
struct dom_nodelist *list)
{
struct dom_doc_nl *l;
@@ -1135,97 +1506,175 @@ void dom_document_remove_nodelist(struct dom_document *doc,
}
/**
- * Get a namednodemap, creating one if necessary
+ * Find element with certain ID in the subtree rooted at root
*
- * \param doc The document to get a namednodemap for
- * \param head Start of list containing items in map
- * \param type The type of items in map
- * \param map Pointer to location to receive map
- * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion.
- *
- * The returned map will have its reference count increased. It is
- * the responsibility of the caller to unref the map once it has
- * finished with it.
+ * \param root The root element from where we start
+ * \param id The ID of the target element
+ * \param result The result element
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
*/
-dom_exception dom_document_get_namednodemap(struct dom_document *doc,
- struct dom_node_internal *head, dom_node_type type,
- struct dom_namednodemap **map)
+dom_exception _dom_find_element_by_id(dom_node_internal *root,
+ struct lwc_string_s *id, struct dom_element **result)
+{
+ *result = NULL;
+ dom_node_internal *node = root;
+
+ while (node != NULL) {
+ if (root->type == DOM_ELEMENT_NODE) {
+ lwc_string *real_id;
+ _dom_element_get_id((dom_element *) node, &real_id);
+ if (real_id == id) {
+ *result = (dom_element *) node;
+ return DOM_NO_ERR;
+ }
+ }
+
+ if (node->first_child != NULL) {
+ /* Has children */
+ node = node->first_child;
+ } else if (node->next != NULL) {
+ /* No children, but has siblings */
+ node = node->next;
+ } else {
+ /* No children or siblings.
+ * Find first unvisited relation. */
+ struct dom_node_internal *parent = node->parent;
+
+ while (parent != root &&
+ node == parent->last_child) {
+ node = parent;
+ parent = parent->parent;
+ }
+
+ node = node->next;
+ }
+ }
+
+ return DOM_NO_ERR;
+}
+
+/**
+ * Duplicate a Node
+ *
+ * \param doc The documen
+ * \param node The node to duplicate
+ * \param deep Whether to make a deep copy
+ * \param result The returned node
+ * \param opt Whether this is adopt or import operation
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ */
+dom_exception dom_document_dup_node(dom_document *doc, struct dom_node *node,
+ bool deep, struct dom_node **result, dom_node_operation opt)
{
- struct dom_doc_nnm *m;
dom_exception err;
+ dom_node_internal *n = (dom_node_internal *) node;
- for (m = doc->maps; m; m = m->next) {
- if (dom_namednodemap_match(m->map, head, type))
- break;
+ if (opt == DOM_NODE_ADOPTED && _dom_node_readonly(n))
+ return DOM_NO_MODIFICATION_ALLOWED_ERR;
+
+ if (n->type == DOM_DOCUMENT_NODE ||
+ n->type == DOM_DOCUMENT_TYPE_NODE)
+ return DOM_NOT_SUPPORTED_ERR;
+
+ err = dom_node_alloc(doc, node, result);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ err = dom_node_copy(*result, node);
+ if (err != DOM_NO_ERR) {
+ _dom_document_alloc(doc, *result, 0);
+ return err;
}
- if (m != NULL) {
- /* Found an existing map, so use it */
- dom_namednodemap_ref(m->map);
- } else {
- /* No existing map */
+ if (n->type == DOM_ATTRIBUTE_NODE) {
+ _dom_attr_set_specified((dom_attr *) node, true);
+ deep = true;
+ }
- /* Create active map entry */
- m = doc->alloc(NULL, sizeof(struct dom_doc_nnm), doc->pw);
- if (m == NULL)
- return DOM_NO_MEM_ERR;
+ if (n->type == DOM_ENTITY_REFERENCE_NODE) {
+ deep = false;
+ }
- /* Create namednodemap */
- err = dom_namednodemap_create(doc, head, type, &m->map);
- if (err != DOM_NO_ERR) {
- doc->alloc(m, 0, doc->pw);
- return err;
- }
+ if (n->type == DOM_ELEMENT_NODE) {
+ /* Specified attributes are copyied but not default attributes,
+ * if the document object hold all the default attributes, we
+ * have nothing to do here */
+ }
- /* Add to document's list of active namednodemaps */
- m->prev = NULL;
- m->next = doc->maps;
- if (doc->maps)
- doc->maps->prev = m;
- doc->maps = m;
+ if (opt == DOM_NODE_ADOPTED && (n->type == DOM_ENTITY_NODE ||
+ n->type == DOM_NOTATION_NODE)) {
+ /* We did not support XML now */
+ return DOM_NOT_SUPPORTED_ERR;
}
- /* Note: the document does not claim a reference on the namednodemap
- * If it did, the map's reference count would never reach zero,
- * and the list would remain indefinitely. This is not a problem as
- * the map notifies the document of its destruction via
- * dom_document_remove_namednodempa. */
+ dom_node_internal *child, *r;
+ if (deep == true) {
+ child = ((dom_node_internal *) node)->first_child;
+ while (child != NULL) {
+ err = dom_document_import_node(doc, child, deep,
+ (void *) &r);
+ if (err != DOM_NO_ERR) {
+ _dom_document_alloc(doc, *result, 0);
+ return err;
+ }
- *map = m->map;
+ err = dom_node_append_child(*result, r, (void *) &r);
+ if (err != DOM_NO_ERR) {
+ _dom_document_alloc(doc, *result, 0);
+ dom_node_unref(r);
+ return err;
+ }
+ dom_node_unref(r);
+
+ child = child->next;
+ }
+ }
+
+ /* Call the dom_user_data_handlers */
+ dom_user_data *ud;
+ ud = n->user_data;
+ while (ud != NULL) {
+ if (ud->handler != NULL)
+ ud->handler(opt, ud->key, ud->data,
+ node, *result);
+ ud = ud->next;
+ }
return DOM_NO_ERR;
}
/**
- * Remove a namednodemap
+ * Try to destory the document.
+ *
+ * \param doc The instance of Document
+ *
+ * Delete the document if:
+ * 1. The refcnt reach zero
+ * 2. The pending list is empty
*
- * \param doc The document to remove the map from
- * \param map The map to remove
+ * else, do nothing.
*/
-void dom_document_remove_namednodemap(struct dom_document *doc,
- struct dom_namednodemap *map)
+void _dom_document_try_destroy(struct dom_document *doc)
{
- struct dom_doc_nnm *m;
-
- for (m = doc->maps; m; m = m->next) {
- if (m->map == map)
- break;
- }
-
- if (m == NULL) {
- /* This should never happen; we should probably abort here */
+ if (doc->base.refcnt != 0 || doc->base.parent != NULL)
return;
- }
-
- /* Remove from list */
- if (m->prev != NULL)
- m->prev->next = m->next;
- else
- doc->maps = m->next;
- if (m->next != NULL)
- m->next->prev = m->prev;
+ _dom_document_destroy((dom_node_internal *) doc);
+}
- /* And free item */
- doc->alloc(m, 0, doc->pw);
+/**
+ * Set the ID attribute name of this document
+ *
+ * \param doc The document object
+ * \param name The ID name of the elements in this document
+ *
+ * @note: The lwc_context of the param 'name' must be the same one with
+ * document's, this should be assured by the client.
+ */
+void _dom_document_set_id_name(dom_document *doc, struct lwc_string_s *name)
+{
+ if (doc->id_name != NULL)
+ lwc_context_string_unref(doc->context, doc->id_name);
+ doc->id_name = lwc_context_string_ref(doc->context, name);
}
+
diff --git a/src/core/document.h b/src/core/document.h
index f05b9e0..145eddf 100644
--- a/src/core/document.h
+++ b/src/core/document.h
@@ -12,9 +12,14 @@
#include <stddef.h>
#include <dom/core/node.h>
-#include <dom/core/string.h>
+#include "core/string.h"
#include "core/node.h"
+#include "core/nodelist.h"
+
+#include "utils/hashtable.h"
+#include "utils/resource_mgr.h"
+#include "utils/list.h"
struct dom_document;
struct dom_namednodemap;
@@ -32,7 +37,6 @@ struct dom_entity_reference;
struct dom_configuration;
struct dom_doc_nl;
-struct dom_doc_nnm;
/**
* DOM document
@@ -46,14 +50,40 @@ struct dom_document {
struct dom_doc_nl *nodelists; /**< List of active nodelists */
- struct dom_doc_nnm *maps; /**< List of active namednodemaps */
+ struct dom_string *uri; /**< The uri of this document */
- struct dom_string **nodenames; /**< Interned nodenames */
+ struct lwc_context_s *context; /**< The internment context */
dom_alloc alloc; /**< Memory (de)allocation function */
void *pw; /**< Pointer to client data */
+
+ struct list_entry pending_nodes;
+ /**< The deletion pending list */
+
+ struct lwc_string_s *id_name; /**< The ID attribute's name */
};
+/* Initialise the document */
+dom_exception _dom_document_initialise(struct dom_document *doc,
+ struct dom_implementation *impl, dom_alloc alloc, void *pw,
+ struct lwc_context_s *ctx);
+
+/* Finalise the document */
+bool _dom_document_finalise(struct dom_document *doc);
+
+/* Create a dom_string from C string */
+dom_exception _dom_document_create_string(struct dom_document *doc,
+ const uint8_t *data, size_t len, struct dom_string **result);
+/* Create a lwc_string from C string */
+dom_exception _dom_document_create_lwcstring(struct dom_document *doc,
+ const uint8_t *data, size_t len, struct lwc_string_s **result);
+/* Create a dom_string from a lwc_string */
+dom_exception _dom_document_create_string_from_lwcstring(
+ struct dom_document *doc, struct lwc_string_s *str,
+ struct dom_string **result);
+
+
+/* Begin the virtual functions */
dom_exception _dom_document_get_doctype(struct dom_document *doc,
struct dom_document_type **result);
dom_exception _dom_document_get_implementation(struct dom_document *doc,
@@ -156,34 +186,66 @@ dom_exception _dom_document_rename_node(struct dom_document *doc,
_dom_document_get_dom_config, \
_dom_document_normalize, \
_dom_document_rename_node
+/* End of vtable */
+
+/* Following comes the protected vtable */
+void _dom_document_destroy(struct dom_node_internal *node);
+dom_exception __dom_document_alloc(struct dom_document *doc,
+ struct dom_node_internal *n, struct dom_node_internal **ret);
+dom_exception _dom_document_copy(struct dom_node_internal *new,
+ struct dom_node_internal *old);
-/* Initialise the document module */
-dom_exception _dom_document_initialise(dom_alloc alloc, void *pw);
-/* Finalise the document module */
-dom_exception _dom_document_finalise(void);
+#define DOM_DOCUMENT_PROTECT_VTABLE \
+ _dom_document_destroy, \
+ __dom_document_alloc, \
+ _dom_document_copy
-/* Destroy a document */
-void dom_document_destroy(struct dom_node_internal *dnode);
+/*---------------------------- Helper functions ---------------------------*/
+
+/* Try to destroy the document:
+ * When the refcnt is zero and the pending list is empty, we can destroy this
+ * document. */
+void _dom_document_try_destroy(struct dom_document *doc);
/* (De)allocate memory */
-void *dom_document_alloc(struct dom_document *doc, void *ptr, size_t size);
+void *_dom_document_alloc(struct dom_document *doc, void *ptr, size_t size);
+
+/* Get the internment context */
+inline struct lwc_context_s *_dom_document_get_intern_context(
+ struct dom_document *doc);
+
+/* Get the resource manager inside this document, a resource manager
+ * is an object which contain the memory allocator/intern string context,
+ * with which we can allocate strings or intern strings */
+void _dom_document_get_resource_mgr(
+ struct dom_document *doc, struct dom_resource_mgr *rm);
+
+/* Get the internal allocator and its pointer */
+inline void _dom_document_get_allocator(struct dom_document *doc,
+ dom_alloc *al, void **pw);
+
+/* Create a hash_table */
+dom_exception _dom_document_create_hashtable(struct dom_document *doc,
+ size_t chains, dom_hash_func f, struct dom_hash_table **ht);
/* Get a nodelist, creating one if necessary */
-dom_exception dom_document_get_nodelist(struct dom_document *doc,
- struct dom_node_internal *root, struct dom_string *tagname,
- struct dom_string *namespace, struct dom_string *localname,
- struct dom_nodelist **list);
+dom_exception _dom_document_get_nodelist(struct dom_document *doc,
+ nodelist_type type, struct dom_node_internal *root,
+ struct lwc_string_s *tagname, struct lwc_string_s *namespace,
+ struct lwc_string_s *localname, struct dom_nodelist **list);
/* Remove a nodelist */
-void dom_document_remove_nodelist(struct dom_document *doc,
+void _dom_document_remove_nodelist(struct dom_document *doc,
struct dom_nodelist *list);
-/* Get a namednodemap, creating one if necessary */
-dom_exception dom_document_get_namednodemap(struct dom_document *doc,
- struct dom_node_internal *head, dom_node_type type,
- struct dom_namednodemap **map);
-/* Remove a namednodemap */
-void dom_document_remove_namednodemap(struct dom_document *doc,
- struct dom_namednodemap *map);
+/* Find element with certain ID in the subtree rooted at root */
+dom_exception _dom_find_element_by_id(dom_node_internal *root,
+ struct lwc_string_s *id, struct dom_element **result);
+
+/* Set the ID attribute name of this document */
+void _dom_document_set_id_name(struct dom_document *doc,
+ struct lwc_string_s *name);
+
+#define _dom_document_get_id_name(d) (d->id_name)
#endif
diff --git a/src/core/document_type.c b/src/core/document_type.c
index fc1a1e9..fd59ef1 100644
--- a/src/core/document_type.c
+++ b/src/core/document_type.c
@@ -4,15 +4,20 @@
* http://www.opensource.org/licenses/mit-license.php
* Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
* Copyright 2007 James Shaw <jshaw@netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
*/
+#include <assert.h>
+
#include <dom/core/document_type.h>
-#include <dom/core/string.h>
#include <dom/bootstrap/implpriv.h>
+#include "core/string.h"
#include "core/document_type.h"
#include "core/node.h"
#include "utils/utils.h"
+#include "utils/namespace.h"
+#include "utils/resource_mgr.h"
/**
* DOM DocumentType node
@@ -20,12 +25,12 @@
struct dom_document_type {
struct dom_node_internal base; /**< Base node */
- /** \todo other members */
+ struct dom_implementation *impl; /**< Owning implementation */
+
struct dom_string *public_id; /**< Doctype public ID */
struct dom_string *system_id; /**< Doctype system ID */
- dom_alloc alloc; /**< Memory (de)allocation function */
- void *pw; /**< Pointer to private data */
+ struct dom_resource_mgr res; /**< resource_mgr of this node */
};
static struct dom_document_type_vtable document_type_vtable = {
@@ -35,6 +40,15 @@ static struct dom_document_type_vtable document_type_vtable = {
DOM_DOCUMENT_TYPE_VTABLE
};
+static struct dom_node_protect_vtable dt_protect_vtable = {
+ DOM_DT_PROTECT_VTABLE
+};
+
+
+/*----------------------------------------------------------------------*/
+
+/* Constructors and destructors */
+
/**
* Create a document type node
*
@@ -52,7 +66,8 @@ static struct dom_document_type_vtable document_type_vtable = {
*/
dom_exception dom_document_type_create(struct dom_string *qname,
struct dom_string *public_id, struct dom_string *system_id,
- dom_alloc alloc, void *pw, struct dom_document_type **doctype)
+ dom_alloc alloc, void *pw, struct lwc_context_s *ctx,
+ struct dom_document_type **doctype)
{
struct dom_document_type *result;
dom_exception err;
@@ -62,28 +77,12 @@ dom_exception dom_document_type_create(struct dom_string *qname,
if (result == NULL)
return DOM_NO_MEM_ERR;
- /* Initialise base node */
- err = dom_node_initialise(&result->base, NULL, DOM_DOCUMENT_TYPE_NODE,
- qname, NULL, NULL, NULL);
- if (err != DOM_NO_ERR) {
- alloc(result, 0, pw);
- return err;
- }
-
/* Initialise the vtable */
result->base.base.vtable = &document_type_vtable;
- result->base.destroy = &dom_document_type_destroy;
-
- /* Get public and system IDs */
- dom_string_ref(public_id);
- result->public_id = public_id;
-
- dom_string_ref(system_id);
- result->system_id = system_id;
-
- /* Fill in allocation information */
- result->alloc = alloc;
- result->pw = pw;
+ result->base.vtable = &dt_protect_vtable;
+
+ err = _dom_document_type_initialise(result, qname, public_id, system_id,
+ alloc, pw, ctx);
*doctype = result;
@@ -97,22 +96,108 @@ dom_exception dom_document_type_create(struct dom_string *qname,
*
* The contents of ::doctype will be destroyed and ::doctype will be freed.
*/
-void dom_document_type_destroy(struct dom_node_internal *doctypenode)
+void _dom_document_type_destroy(struct dom_node_internal *doctypenode)
{
struct dom_document_type *doctype =
(struct dom_document_type *)doctypenode;
- /* Finish with public and system IDs */
- dom_string_unref(doctype->system_id);
- dom_string_unref(doctype->public_id);
-
/* Finalise base class */
- dom_node_finalise(doctype->base.owner, &doctype->base);
+ _dom_document_type_finalise(doctype);
/* Free doctype */
- doctype->alloc(doctype, 0, doctype->pw);
+ doctype->res.alloc(doctype, 0, doctype->res.pw);
}
+/* Initialise this document_type */
+dom_exception _dom_document_type_initialise(struct dom_document_type *doctype,
+ struct dom_string *qname, struct dom_string *public_id,
+ struct dom_string *system_id, dom_alloc alloc, void *pw,
+ struct lwc_context_s *ctx)
+{
+ dom_exception err;
+
+ dom_string *prefix, *localname;
+ err = _dom_namespace_split_qname(qname, &prefix, &localname);
+ if (err != DOM_NO_ERR) {
+ alloc(doctype, 0, pw);
+ return err;
+ }
+
+ lwc_string *lprefix = NULL, *lname = NULL;
+ if (prefix != NULL) {
+ err = _dom_string_intern(prefix, ctx, &lprefix);
+ if (err != DOM_NO_ERR) {
+ dom_string_unref(prefix);
+ dom_string_unref(localname);
+ alloc(doctype, 0, pw);
+ return err;
+ }
+ }
+
+ if (localname != NULL) {
+ err = _dom_string_intern(localname, ctx, &lname);
+ if (err != DOM_NO_ERR) {
+ dom_string_unref(prefix);
+ dom_string_unref(localname);
+ if (lprefix != NULL)
+ lwc_context_string_unref(ctx, lprefix);
+ alloc(doctype, 0, pw);
+ return err;
+ }
+ }
+
+ /* TODO: I should figure out how the namespaceURI can be got */
+
+ /* Initialise base node */
+ err = _dom_node_initialise_generic(&doctype->base, NULL, alloc, pw,
+ ctx, DOM_DOCUMENT_TYPE_NODE, lname, NULL, NULL,
+ lprefix);
+ if (err != DOM_NO_ERR) {
+ alloc(doctype, 0, pw);
+ return err;
+ }
+
+ /* Get public and system IDs */
+ if (public_id != NULL)
+ dom_string_ref(public_id);
+ doctype->public_id = public_id;
+
+ if (system_id != NULL)
+ dom_string_ref(system_id);
+ doctype->system_id = system_id;
+
+ if (prefix != NULL)
+ dom_string_unref(prefix);
+ if (localname != NULL)
+ dom_string_unref(localname);
+
+ /* Fill in allocation information */
+ doctype->res.alloc = alloc;
+ doctype->res.pw = pw;
+ doctype->res.ctx = ctx;
+
+ return DOM_NO_ERR;
+}
+
+/* The destructor function of dom_document_type */
+void _dom_document_type_finalise(struct dom_document_type *doctype)
+{
+ if (doctype->public_id != NULL)
+ dom_string_unref(doctype->public_id);
+ if (doctype->system_id != NULL)
+ dom_string_unref(doctype->system_id);
+
+ assert(doctype->base.owner != NULL || doctype->base.user_data == NULL);
+
+ _dom_node_finalise_generic(&doctype->base, doctype->res.alloc,
+ doctype->res.pw, doctype->res.ctx);
+}
+
+
+/*----------------------------------------------------------------------*/
+
+/* Virtual functions */
+
/**
* Retrieve a document type's name
*
@@ -123,6 +208,9 @@ void dom_document_type_destroy(struct dom_node_internal *doctypenode)
* The returned string will have its reference count increased. It is
* the responsibility of the caller to unref the string once it has
* finished with it.
+ *
+ * We don't support this API now, so this function call should always
+ * return DOM_NOT_SUPPORTED_ERR.
*/
dom_exception _dom_document_type_get_name(struct dom_document_type *doc_type,
struct dom_string **result)
@@ -143,6 +231,9 @@ dom_exception _dom_document_type_get_name(struct dom_document_type *doc_type,
* The returned map will have its reference count increased. It is
* the responsibility of the caller to unref the map once it has
* finished with it.
+ *
+ * We don't support this API now, so this function call should always
+ * return DOM_NOT_SUPPORTED_ERR.
*/
dom_exception _dom_document_type_get_entities(
struct dom_document_type *doc_type,
@@ -164,6 +255,9 @@ dom_exception _dom_document_type_get_entities(
* The returned map will have its reference count increased. It is
* the responsibility of the caller to unref the map once it has
* finished with it.
+ *
+ * We don't support this API now, so this function call should always
+ * return DOM_NOT_SUPPORTED_ERR.
*/
dom_exception _dom_document_type_get_notations(
struct dom_document_type *doc_type,
@@ -185,6 +279,9 @@ dom_exception _dom_document_type_get_notations(
* The returned string will have its reference count increased. It is
* the responsibility of the caller to unref the string once it has
* finished with it.
+ *
+ * We don't support this API now, so this function call should always
+ * return DOM_NOT_SUPPORTED_ERR.
*/
dom_exception _dom_document_type_get_public_id(
struct dom_document_type *doc_type,
@@ -206,6 +303,9 @@ dom_exception _dom_document_type_get_public_id(
* The returned string will have its reference count increased. It is
* the responsibility of the caller to unref the string once it has
* finished with it.
+ *
+ * We don't support this API now, so this function call should always
+ * return DOM_NOT_SUPPORTED_ERR.
*/
dom_exception _dom_document_type_get_system_id(
struct dom_document_type *doc_type,
@@ -227,6 +327,9 @@ dom_exception _dom_document_type_get_system_id(
* The returned string will have its reference count increased. It is
* the responsibility of the caller to unref the string once it has
* finished with it.
+ *
+ * We don't support this API now, so this function call should always
+ * return DOM_NOT_SUPPORTED_ERR.
*/
dom_exception _dom_document_type_get_internal_subset(
struct dom_document_type *doc_type,
@@ -238,3 +341,60 @@ dom_exception _dom_document_type_get_internal_subset(
return DOM_NOT_SUPPORTED_ERR;
}
+/*-----------------------------------------------------------------------*/
+
+/* Overload protected virtual functions */
+
+/* The virtual destroy function of this class */
+void _dom_dt_destroy(struct dom_node_internal *node)
+{
+ _dom_document_type_destroy(node);
+}
+
+/* The memory allocator of this class */
+dom_exception _dom_dt_alloc(struct dom_document *doc,
+ struct dom_node_internal *n, struct dom_node_internal **ret)
+{
+ UNUSED(doc);
+ UNUSED(n);
+ UNUSED(ret);
+
+ return DOM_NOT_SUPPORTED_ERR;
+}
+
+/* The copy constructor of this class */
+dom_exception _dom_dt_copy(struct dom_node_internal *new,
+ struct dom_node_internal *old)
+{
+ UNUSED(new);
+ UNUSED(old);
+
+ return DOM_NOT_SUPPORTED_ERR;
+}
+
+
+/*----------------------------------------------------------------------*/
+
+/* Helper functions */
+
+/* Get the resource manager of this object */
+void _dom_document_type_get_resource_mgr(
+ struct dom_document_type *dt, struct dom_resource_mgr *rm)
+{
+ rm->alloc = dt->res.alloc;
+ rm->pw = dt->res.pw;
+ rm->ctx = dt->res.ctx;
+}
+
+/**
+ * Get the implementation which created this dom_document_type
+ *
+ * \param dt The document type object
+ * \return the dom_implementation instance which creates this node.
+ */
+struct dom_implementation *_dom_document_type_get_impl(
+ struct dom_document_type *dt)
+{
+ return dt->impl;
+}
+
diff --git a/src/core/document_type.h b/src/core/document_type.h
index e38cf52..649b027 100644
--- a/src/core/document_type.h
+++ b/src/core/document_type.h
@@ -9,9 +9,16 @@
#define dom_internal_core_document_type_h_
struct dom_document_type;
+struct dom_resource_mgr;
+struct dom_implementation;
/* Destroy a document type */
-void dom_document_type_destroy(struct dom_node_internal *doctypenode);
+void _dom_document_type_destroy(struct dom_node_internal *doctypenode);
+dom_exception _dom_document_type_initialise(struct dom_document_type *doctype,
+ struct dom_string *qname, struct dom_string *public_id,
+ struct dom_string *system_id, dom_alloc alloc, void *pw,
+ struct lwc_context_s *ctx);
+void _dom_document_type_finalise(struct dom_document_type *doctype);
/* The virtual functions of DocumentType */
dom_exception _dom_document_type_get_name(struct dom_document_type *doc_type,
@@ -40,5 +47,22 @@ dom_exception _dom_document_type_get_internal_subset(
_dom_document_type_get_system_id, \
_dom_document_type_get_internal_subset
-#endif
+/* Following comes the protected vtable */
+void _dom_dt_destroy(struct dom_node_internal *node);
+dom_exception _dom_dt_alloc(struct dom_document *doc,
+ struct dom_node_internal *n, struct dom_node_internal **ret);
+dom_exception _dom_dt_copy(struct dom_node_internal *new,
+ struct dom_node_internal *old);
+
+#define DOM_DT_PROTECT_VTABLE \
+ _dom_dt_destroy, \
+ _dom_dt_alloc, \
+ _dom_dt_copy
+/* Helper functions */
+void _dom_document_type_get_resource_mgr(
+ struct dom_document_type *dt, struct dom_resource_mgr *rm);
+struct dom_implementation *_dom_document_type_get_impl(
+ struct dom_document_type *dt);
+
+#endif
diff --git a/src/core/element.c b/src/core/element.c
index 80d547e..11c7f5e 100644
--- a/src/core/element.c
+++ b/src/core/element.c
@@ -3,31 +3,122 @@
* Licensed under the MIT License,
* http://www.opensource.org/licenses/mit-license.php
* Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
*/
#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <dom/dom.h>
#include <dom/core/attr.h>
#include <dom/core/element.h>
#include <dom/core/node.h>
#include <dom/core/string.h>
+#include <dom/core/document.h>
#include "core/attr.h"
#include "core/document.h"
#include "core/element.h"
#include "core/node.h"
+#include "core/namednodemap.h"
+#include "utils/validate.h"
#include "utils/namespace.h"
#include "utils/utils.h"
+#include "utils/hashtable.h"
+
+/* The three numbers are just random ones, maybe we should change it after some
+ * more consideration */
+#define CHAINS_ATTRIBUTES 31
+#define CHAINS_NAMESPACE 7
+#define CHAINS_NS_ATTRIBUTES 31
static struct dom_element_vtable element_vtable = {
{
- DOM_NODE_VTABLE
+ DOM_NODE_VTABLE_ELEMENT
},
DOM_ELEMENT_VTABLE
};
+static struct dom_node_protect_vtable element_protect_vtable = {
+ DOM_ELEMENT_PROTECT_VTABLE
+};
+
+static dom_exception _dom_element_get_attr(struct dom_element *element,
+ struct dom_hash_table *hs, struct dom_string *name,
+ struct dom_string **value);
+static dom_exception _dom_element_set_attr(struct dom_element *element,
+ struct dom_hash_table *hs, struct dom_string *name,
+ struct dom_string *value);
+static dom_exception _dom_element_remove_attr(struct dom_element *element,
+ struct dom_hash_table *hs, struct dom_string *name);
+static dom_exception _dom_element_get_attr_node(struct dom_element *element,
+ struct dom_hash_table *hs, struct dom_string *name,
+ struct dom_attr **result);
+static dom_exception _dom_element_set_attr_node(struct dom_element *element,
+ struct dom_hash_table *hs, struct dom_attr *attr,
+ struct dom_attr **result);
+static dom_exception _dom_element_remove_attr_node(struct dom_element *element,
+ struct dom_hash_table *hs, struct dom_attr *attr,
+ struct dom_attr **result);
+static dom_exception _dom_element_has_attr(struct dom_element *element,
+ struct dom_hash_table *hs, struct dom_string *name,
+ bool *result);
+static dom_exception _dom_element_set_id_attr(struct dom_element *element,
+ struct dom_hash_table *hs, struct dom_string *name, bool is_id);
+
+static unsigned int _dom_element_hash_lwcstring(void *key);
+
+
+/* The operation set for namednodemap */
+static dom_exception attributes_get_length(void *priv,
+ unsigned long *length);
+static dom_exception attributes_get_named_item(void *priv,
+ struct dom_string *name, struct dom_node **node);
+static dom_exception attributes_set_named_item(void *priv,
+ struct dom_node *arg, struct dom_node **node);
+static dom_exception attributes_remove_named_item(
+ void *priv, struct dom_string *name,
+ struct dom_node **node);
+static dom_exception attributes_item(void *priv,
+ unsigned long index, struct dom_node **node);
+static dom_exception attributes_get_named_item_ns(
+ void *priv, struct dom_string *namespace,
+ struct dom_string *localname, struct dom_node **node);
+static dom_exception attributes_set_named_item_ns(
+ void *priv, struct dom_node *arg,
+ struct dom_node **node);
+static dom_exception attributes_remove_named_item_ns(
+ void *priv, struct dom_string *namespace,
+ struct dom_string *localname, struct dom_node **node);
+static void attributes_destroy(void *priv);
+static bool attributes_equal(void *p1, void *p2);
+
+static struct nnm_operation attributes_opt = {
+ attributes_get_length,
+ attributes_get_named_item,
+ attributes_set_named_item,
+ attributes_remove_named_item,
+ attributes_item,
+ attributes_get_named_item_ns,
+ attributes_set_named_item_ns,
+ attributes_remove_named_item_ns,
+ attributes_destroy,
+ attributes_equal
+};
+
+static void *_key(void *key, void *key_pw, dom_alloc alloc, void *pw,
+ bool clone);
+static void *_value(void *value, void *value_pw, dom_alloc alloc,
+ void *pw, bool clone);
+static void *_nsattributes(void *value, void *value_pw, dom_alloc alloc,
+ void *pw, bool clone);
+
+/*----------------------------------------------------------------------*/
+/* Constructors and Destructors */
+
/**
- * Initialise an element node
+ * Create an element node
*
* \param doc The owning document
* \param name The (local) name of the node to create
@@ -43,41 +134,29 @@ static struct dom_element_vtable element_vtable = {
*
* The returned element will already be referenced.
*/
-dom_exception dom_element_initialise(struct dom_element *el,
- struct dom_string *name, struct dom_string *namespace,
- struct dom_string *prefix, struct dom_element **result)
+dom_exception _dom_element_create(struct dom_document *doc,
+ struct lwc_string_s *name, struct lwc_string_s *namespace,
+ struct lwc_string_s *prefix, struct dom_element **result)
{
- dom_exception err;
- struct dom_document *doc;
-
- dom_node_get_owner_document(el, &doc);
-
- /** \todo Sanity check the tag name */
-
- /* Initialise the base class */
- err = dom_node_initialise(&el->base, doc, DOM_ELEMENT_NODE,
- name, NULL, namespace, prefix);
- if (err != DOM_NO_ERR) {
- dom_document_alloc(doc, el, 0);
- return err;
- }
+ struct dom_element *el;
- /* Perform our type-specific initialisation */
- el->attributes = NULL;
- el->schema_type_info = NULL;
+ /* Allocate the element */
+ el = _dom_document_alloc(doc, NULL, sizeof(struct dom_element));
+ if (el == NULL)
+ return DOM_NO_MEM_ERR;
- /* Init the vtable's destroy function */
+ /* Initialise the vtables */
el->base.base.vtable = &element_vtable;
- el->base.destroy = &_dom_element_destroy;
+ el->base.vtable = &element_protect_vtable;
- *result = el;
-
- return DOM_NO_ERR;
+ return _dom_element_initialise(el, doc, name, namespace, prefix,
+ result);
}
/**
- * Create an element node
+ * Initialise an element node
*
+ * \param el The element
* \param doc The owning document
* \param name The (local) name of the node to create
* \param namespace The namespace URI of the element, or NULL
@@ -87,24 +166,51 @@ dom_exception dom_element_initialise(struct dom_element *el,
* DOM_INVALID_CHARACTER_ERR if ::name is invalid,
* DOM_NO_MEM_ERR on memory exhaustion.
*
+ * The caller should make sure that ::name is a valid NCName.
+ *
* ::doc, ::name, ::namespace and ::prefix will have their
* reference counts increased.
*
* The returned element will already be referenced.
*/
-dom_exception dom_element_create(struct dom_document *doc,
- struct dom_string *name, struct dom_string *namespace,
- struct dom_string *prefix, struct dom_element **result)
+dom_exception _dom_element_initialise(struct dom_element *el,
+ struct dom_document *doc, struct lwc_string_s *name,
+ struct lwc_string_s *namespace, struct lwc_string_s *prefix,
+ struct dom_element **result)
{
- struct dom_element *el;
+ dom_exception err;
- /* Allocate the element */
- el = dom_document_alloc(doc, NULL, sizeof(struct dom_element));
- if (el == NULL)
- return DOM_NO_MEM_ERR;
+ assert(doc != NULL);
+
+ err = _dom_document_create_hashtable(doc, CHAINS_ATTRIBUTES,
+ _dom_element_hash_lwcstring, &el->attributes);
+ if (err != DOM_NO_ERR) {
+ _dom_document_alloc(doc, el, 0);
+ return err;
+ }
+
+ err = _dom_document_create_hashtable(doc, CHAINS_NAMESPACE,
+ _dom_element_hash_lwcstring, &el->ns_attributes);
+ if (err != DOM_NO_ERR) {
+ _dom_document_alloc(doc, el, 0);
+ _dom_document_alloc(doc, el->attributes, 0);
+ return err;
+ }
+ /* Initialise the base class */
+ err = _dom_node_initialise(&el->base, doc, DOM_ELEMENT_NODE,
+ name, NULL, namespace, prefix);
+ if (err != DOM_NO_ERR) {
+ _dom_document_alloc(doc, el, 0);
+ return err;
+ }
+
+ /* Perform our type-specific initialisation */
+ el->id_ns = NULL;
+ el->id_name = NULL;
+ el->schema_type_info = NULL;
+
+ *result = el;
- dom_element_initialise(el, name, namespace, prefix, result);
-
return DOM_NO_ERR;
}
@@ -116,54 +222,22 @@ dom_exception dom_element_create(struct dom_document *doc,
*
* The contents of ::element will be destroyed and ::element will be freed.
*/
-void dom_element_destroy(struct dom_document *doc,
+void _dom_element_destroy(struct dom_document *doc,
struct dom_element *element)
{
- struct dom_node_internal *c, *d;
-
- /* Destroy children of this node */
- for (c = element->base.first_child; c != NULL; c = d) {
- d = c->next;
-
- /* Detach child */
- c->parent = NULL;
-
- if (c->refcnt > 0) {
- /* Something is using this child */
-
- /** \todo add to list of nodes pending deletion */
-
- continue;
- }
-
- /* Detach from sibling list */
- c->previous = NULL;
- c->next = NULL;
-
- dom_node_destroy(c);
- }
+ lwc_context *ctx = _dom_document_get_intern_context(doc);
+ assert (ctx != NULL);
/* Destroy attributes attached to this node */
- for (c = (struct dom_node_internal *) element->attributes;
- c != NULL; c = d) {
- d = c->next;
-
- /* Detach child */
- c->parent = NULL;
-
- if (c->refcnt > 0) {
- /* Something is using this attribute */
-
- /** \todo add to list of nodes pending deletion */
-
- continue;
- }
-
- /* Detach from sibling list */
- c->previous = NULL;
- c->next = NULL;
+ if (element->attributes != NULL) {
+ _dom_hash_destroy(element->attributes, _key, ctx, _value, ctx);
+ element->attributes = NULL;
+ }
- dom_node_destroy(c);
+ if (element->ns_attributes != NULL) {
+ _dom_hash_destroy(element->ns_attributes, _key, ctx,
+ _nsattributes, ctx);
+ element->ns_attributes = NULL;
}
if (element->schema_type_info != NULL) {
@@ -171,24 +245,15 @@ void dom_element_destroy(struct dom_document *doc,
}
/* Finalise base class */
- dom_node_finalise(doc, &element->base);
+ _dom_node_finalise(doc, &element->base);
/* Free the element */
- dom_document_alloc(doc, element, 0);
+ _dom_document_alloc(doc, element, 0);
}
-/**
- * The destroy virtual function of dom_element
- *
- * \param element The element to be destroyed
- **/
-void _dom_element_destroy(struct dom_node_internal *node)
-{
- struct dom_document *doc;
- dom_node_get_owner_document(node, &doc);
+/*----------------------------------------------------------------------*/
- dom_element_destroy(doc, (struct dom_element *) node);
-}
+/* The public virtual functions */
/**
* Retrieve an element's tag name
@@ -224,23 +289,7 @@ dom_exception _dom_element_get_tag_name(struct dom_element *element,
dom_exception _dom_element_get_attribute(struct dom_element *element,
struct dom_string *name, struct dom_string **value)
{
- struct dom_node_internal *a = (struct dom_node_internal *)
- element->attributes;
-
- /* Search attributes, looking for name */
- for (; a != NULL; a = a->next) {
- if (dom_string_cmp(a->name, name) == 0)
- break;
- }
-
- /* Fill in value */
- if (a == NULL) {
- *value = NULL;
- } else {
- dom_attr_get_value(((struct dom_attr *) a), value);
- }
-
- return DOM_NO_ERR;
+ return _dom_element_get_attr(element, element->attributes, name, value);
}
/**
@@ -256,58 +305,7 @@ dom_exception _dom_element_get_attribute(struct dom_element *element,
dom_exception _dom_element_set_attribute(struct dom_element *element,
struct dom_string *name, struct dom_string *value)
{
- struct dom_node_internal *e = (struct dom_node_internal *) element;
- struct dom_node_internal *a = (struct dom_node_internal *)
- element->attributes;
-
- /** \todo validate name */
-
- /* Ensure element can be written to */
- if (_dom_node_readonly(e))
- return DOM_NO_MODIFICATION_ALLOWED_ERR;
-
- /* Search for existing attribute with same name */
- for (; a != NULL; a = a->next) {
- if (dom_string_cmp(a->name, name) == 0)
- break;
- }
-
- if (a != NULL) {
- /* Found an existing attribute, so replace its value */
- dom_exception err;
-
- err = dom_attr_set_value((struct dom_attr *) a, value);
- if (err != DOM_NO_ERR)
- return err;
- } else {
- /* No existing attribute, so create one */
- dom_exception err;
- struct dom_attr *attr;
-
- err = dom_attr_create(e->owner, name, NULL, NULL, &attr);
- if (err != DOM_NO_ERR)
- return err;
-
- /* Set its value */
- err = dom_attr_set_value(attr, value);
- if (err != DOM_NO_ERR) {
- dom_node_unref((struct dom_node *) attr);
- return err;
- }
-
- a = (struct dom_node_internal *) attr;
-
- /* And insert it into the element */
- a->previous = NULL;
- a->next = (struct dom_node_internal *) element->attributes;
-
- if (a->next != NULL)
- a->next->previous = a;
-
- element->attributes = attr;
- }
-
- return DOM_NO_ERR;
+ return _dom_element_set_attr(element, element->attributes, name, value);
}
/**
@@ -321,39 +319,7 @@ dom_exception _dom_element_set_attribute(struct dom_element *element,
dom_exception _dom_element_remove_attribute(struct dom_element *element,
struct dom_string *name)
{
- struct dom_node_internal *e = (struct dom_node_internal *) element;
- struct dom_node_internal *a = (struct dom_node_internal *)
- element->attributes;
-
- /* Ensure element can be written to */
- if (_dom_node_readonly(e))
- return DOM_NO_MODIFICATION_ALLOWED_ERR;
-
- /* Search for existing attribute with same name */
- for (; a != NULL; a = a->next) {
- if (dom_string_cmp(a->name, name) == 0)
- break;
- }
-
- /* Detach attr node from list */
- if (a != NULL) {
- if (a->previous != NULL)
- a->previous->next = a->next;
- else
- element->attributes = (struct dom_attr *) a->next;
-
- if (a->next != NULL)
- a->next->previous = a->previous;
-
- a->previous = a->next = a->parent = NULL;
-
- /* And destroy attr */
- dom_node_unref(a);
- }
-
- /** \todo defaulted attribute handling */
-
- return DOM_NO_ERR;
+ return _dom_element_remove_attr(element, element->attributes, name);
}
/**
@@ -368,23 +334,11 @@ dom_exception _dom_element_remove_attribute(struct dom_element *element,
* the responsibility of the caller to unref the node once it has
* finished with it.
*/
-dom_exception _dom_element_get_attribute_node(struct dom_element *element,
+dom_exception _dom_element_get_attribute_node(struct dom_element *element,
struct dom_string *name, struct dom_attr **result)
{
- struct dom_node_internal *a = (struct dom_node_internal *)
- element->attributes;
-
- /* Search attributes, looking for name */
- for (; a != NULL; a = a->next) {
- if (dom_string_cmp(a->name, name) == 0)
- break;
- }
-
- if (a != NULL)
- dom_node_ref(a);
- *result = (struct dom_attr *) a;
-
- return DOM_NO_ERR;
+ return _dom_element_get_attr_node(element, element->attributes, name,
+ result);
}
/**
@@ -407,78 +361,8 @@ dom_exception _dom_element_get_attribute_node(struct dom_element *element,
dom_exception _dom_element_set_attribute_node(struct dom_element *element,
struct dom_attr *attr, struct dom_attr **result)
{
- struct dom_node_internal *e = (struct dom_node_internal *) element;
- struct dom_node_internal *a = (struct dom_node_internal *) attr;
- struct dom_attr *prev = NULL;
-
- /* Ensure element and attribute belong to the same document */
- if (e->owner != a->owner)
- return DOM_WRONG_DOCUMENT_ERR;
-
- /* Ensure element can be written to */
- if (_dom_node_readonly(e))
- return DOM_NO_MODIFICATION_ALLOWED_ERR;
-
- /* Ensure attribute isn't attached to another element */
- if (a->parent != NULL && a->parent != e)
- return DOM_INUSE_ATTRIBUTE_ERR;
-
- /* Attach attr to element, if not already attached */
- if (a->parent == NULL) {
-
- /* Search for existing attribute with same name */
- prev = element->attributes;
- while (prev != NULL) {
- struct dom_node_internal *p =
- (struct dom_node_internal *) prev;
-
- if (dom_string_cmp(a->name, p->name) == 0)
- break;
-
- prev = (struct dom_attr *) p->next;
- }
-
- a->parent = e;
-
- if (prev != NULL) {
- /* Found an existing attribute, so replace it */
- struct dom_node_internal *p =
- (struct dom_node_internal *) prev;
-
- a->previous = p->previous;
- a->next = p->next;
-
- if (a->previous != NULL)
- a->previous->next = a;
- else
- element->attributes = attr;
-
- if (a->next != NULL)
- a->next->previous = a;
-
- /* Invalidate existing attribute's location info */
- p->next = NULL;
- p->previous = NULL;
- p->parent = NULL;
- } else {
- /* No existing attribute, so insert at front of list */
- a->previous = NULL;
- a->next = (struct dom_node_internal *)
- element->attributes;
-
- if (a->next != NULL)
- a->next->previous = a;
-
- element->attributes = attr;
- }
- }
-
- if (prev != NULL)
- dom_node_ref((struct dom_node *) prev);
-
- *result = prev;
-
- return DOM_NO_ERR;
+ return _dom_element_set_attr_node(element, element->attributes, attr,
+ result);
}
/**
@@ -499,35 +383,8 @@ dom_exception _dom_element_set_attribute_node(struct dom_element *element,
dom_exception _dom_element_remove_attribute_node(struct dom_element *element,
struct dom_attr *attr, struct dom_attr **result)
{
- struct dom_node_internal *e = (struct dom_node_internal *) element;
- struct dom_node_internal *a = (struct dom_node_internal *) attr;
-
- /* Ensure element can be written to */
- if (_dom_node_readonly(e))
- return DOM_NO_MODIFICATION_ALLOWED_ERR;
-
- /* Ensure attr is an attribute of element */
- if (a->parent != e)
- return DOM_NOT_FOUND_ERR;
-
- /* Detach attr node from list */
- if (a->previous != NULL)
- a->previous->next = a->next;
- else
- element->attributes = (struct dom_attr *) a->next;
-
- if (a->next != NULL)
- a->next->previous = a->previous;
-
- a->previous = a->next = a->parent = NULL;
-
- /** \todo defaulted attribute handling */
-
- /* Return the detached node */
- dom_node_ref(a);
- *result = attr;
-
- return DOM_NO_ERR;
+ return _dom_element_remove_attr_node(element, element->attributes,
+ attr, result);
}
/**
@@ -547,9 +404,25 @@ dom_exception _dom_element_get_elements_by_tag_name(
struct dom_element *element, struct dom_string *name,
struct dom_nodelist **result)
{
- return dom_document_get_nodelist(element->base.owner,
- (struct dom_node_internal *) element, name, NULL,
+ dom_exception err;
+ lwc_string *n;
+ lwc_context *ctx;
+ dom_node_internal *base = (dom_node_internal *) element;
+
+ assert(base->owner != NULL);
+ ctx = _dom_document_get_intern_context(base->owner);
+ assert(ctx != NULL);
+
+ err = _dom_string_intern(name, ctx, &n);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ err = _dom_document_get_nodelist(base->owner, DOM_NODELIST_BY_NAME,
+ (struct dom_node_internal *) element, n, NULL,
NULL, result);
+
+ lwc_context_string_unref(ctx, n);
+ return err;
}
/**
@@ -573,28 +446,26 @@ dom_exception _dom_element_get_attribute_ns(struct dom_element *element,
struct dom_string *namespace, struct dom_string *localname,
struct dom_string **value)
{
- struct dom_node_internal *a = (struct dom_node_internal *)
- element->attributes;
-
- /** \todo ensure implementation supports XML */
-
- /* Search attributes, looking for namespace/localname pair */
- for (; a != NULL; a = a->next) {
- if (((namespace == NULL && a->namespace == NULL) ||
- (namespace != NULL &&
- dom_string_cmp(a->namespace, namespace) == 0)) &&
- dom_string_cmp(a->name, localname) == 0)
- break;
- }
+ lwc_string *str;
+ dom_exception err;
+ struct dom_hash_table *attrs;
- /* Fill in value */
- if (a == NULL) {
+ if (namespace == NULL)
+ return _dom_element_get_attribute(element, localname, value);
+
+ err = _dom_node_get_intern_string(&element->base, namespace, &str);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ attrs = (struct dom_hash_table *) _dom_hash_get(element->ns_attributes,
+ str);
+ /* The element has no such namespace */
+ if (attrs == NULL) {
*value = NULL;
- } else {
- dom_attr_get_value(((struct dom_attr *) a), value);
+ return DOM_NO_ERR;
}
- return DOM_NO_ERR;
+ return _dom_element_get_attr(element, attrs, localname, value);
}
/**
@@ -630,101 +501,56 @@ dom_exception _dom_element_set_attribute_ns(struct dom_element *element,
struct dom_string *namespace, struct dom_string *qname,
struct dom_string *value)
{
- struct dom_node_internal *e = (struct dom_node_internal *) element;
- struct dom_node_internal *a = (struct dom_node_internal *)
- element->attributes;
- struct dom_string *prefix, *localname;
+ lwc_string *str;
dom_exception err;
+ struct dom_hash_table *attrs;
+ bool added;
- /** \todo ensure XML feature is supported */
+ if (_dom_validate_name(qname) == false)
+ return DOM_INVALID_CHARACTER_ERR;
- /* Validate name */
err = _dom_namespace_validate_qname(qname, namespace);
- if (err != DOM_NO_ERR) {
- return err;
- }
+ if (err != DOM_NO_ERR)
+ return DOM_NAMESPACE_ERR;
- /* Ensure element can be written to */
- if (_dom_node_readonly(e)) {
- return DOM_NO_MODIFICATION_ALLOWED_ERR;
- }
-
- /* Decompose QName */
+ dom_string *localname;
+ dom_string *prefix;
err = _dom_namespace_split_qname(qname, &prefix, &localname);
- if (err != DOM_NO_ERR) {
+ if (err != DOM_NO_ERR)
return err;
- }
- /* Search for existing attribute with same namespace/localname */
- for (; a != NULL; a = a->next) {
- if (((namespace == NULL && a->namespace == NULL) ||
- (namespace != NULL &&
- dom_string_cmp(a->namespace, namespace) == 0)) &&
- dom_string_cmp(a->name, localname) == 0)
- break;
+ /* If there is no namespace, redirect to set_attribute */
+ if (namespace == NULL) {
+ if (prefix != NULL)
+ return DOM_NAMESPACE_ERR;
+ err = _dom_element_set_attribute(element, localname, value);
+ dom_string_unref(localname);
+ return err;
}
- if (a != NULL) {
- /* Found an existing attribute, so replace its prefix & value */
- dom_exception err;
-
- err = dom_node_set_prefix(a, prefix);
- if (err != DOM_NO_ERR) {
- if (prefix != NULL) {
- dom_string_unref(prefix);
- }
- dom_string_unref(localname);
- return err;
- }
-
- err = dom_attr_set_value((struct dom_attr *) a, value);
- if (err != DOM_NO_ERR) {
- if (prefix != NULL) {
- dom_string_unref(prefix);
- }
- dom_string_unref(localname);
- return err;
- }
- } else {
- /* No existing attribute, so create one */
- dom_exception err;
- struct dom_attr *attr;
-
- err = dom_attr_create(e->owner, localname,
- namespace, prefix, &attr);
- if (err != DOM_NO_ERR) {
- if (prefix != NULL) {
- dom_string_unref(prefix);
- }
- dom_string_unref(localname);
- return err;
- }
-
- /* Set its value */
- err = dom_attr_set_value(attr, value);
- if (err != DOM_NO_ERR) {
- dom_node_unref((struct dom_node *) attr);
-
- if (prefix != NULL) {
- dom_string_unref(prefix);
- }
- dom_string_unref(localname);
+ err = _dom_node_get_intern_string(&element->base, namespace, &str);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ attrs = (struct dom_hash_table *) _dom_hash_get(element->ns_attributes,
+ str);
+ /* The element has no such namespace */
+ if (attrs == NULL) {
+ dom_document *doc;
+ doc = dom_node_get_owner(element);
+ assert(doc != NULL);
+ err = _dom_document_create_hashtable(doc, CHAINS_NS_ATTRIBUTES,
+ _dom_element_hash_lwcstring, &attrs);
+ if (err != DOM_NO_ERR)
return err;
- }
- a = (struct dom_node_internal *) attr;
-
- /* And insert it into the element */
- a->previous = NULL;
- a->next = (struct dom_node_internal *) element->attributes;
-
- if (a->next != NULL)
- a->next->previous = a;
-
- element->attributes = attr;
+ added = _dom_hash_add(element->ns_attributes, str, attrs,
+ false);
+ if (added == false)
+ return DOM_NO_MEM_ERR;
}
- return DOM_NO_ERR;
+ return _dom_element_set_attr(element, attrs, localname, value);
}
/**
@@ -744,44 +570,25 @@ dom_exception _dom_element_set_attribute_ns(struct dom_element *element,
dom_exception _dom_element_remove_attribute_ns(struct dom_element *element,
struct dom_string *namespace, struct dom_string *localname)
{
- struct dom_node_internal *e = (struct dom_node_internal *) element;
- struct dom_node_internal *a = (struct dom_node_internal *)
- element->attributes;
-
- /** \todo ensure XML feature is supported */
-
- /* Ensure element can be written to */
- if (_dom_node_readonly(e))
- return DOM_NO_MODIFICATION_ALLOWED_ERR;
-
- /* Search for existing attribute with same namespace/localname */
- for (; a != NULL; a = a->next) {
- if (((namespace == NULL && a->namespace == NULL) ||
- (namespace != NULL &&
- dom_string_cmp(a->namespace, namespace) == 0)) &&
- dom_string_cmp(a->name, localname) == 0)
- break;
- }
-
- /* Detach attr node from list */
- if (a != NULL) {
- if (a->previous != NULL)
- a->previous->next = a->next;
- else
- element->attributes = (struct dom_attr *) a->next;
-
- if (a->next != NULL)
- a->next->previous = a->previous;
+ lwc_string *str;
+ dom_exception err;
+ struct dom_hash_table *attrs;
- a->previous = a->next = a->parent = NULL;
+ if (namespace != NULL)
+ return _dom_element_remove_attribute(element, localname);
- /* And destroy attr */
- dom_node_unref(a);
+ err = _dom_node_get_intern_string(&element->base, namespace, &str);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ attrs = (struct dom_hash_table *) _dom_hash_get(element->ns_attributes,
+ str);
+ /* The element has no such namespace */
+ if (attrs == NULL) {
+ return DOM_NO_ERR;
}
- /** \todo defaulted attribute handling */
-
- return DOM_NO_ERR;
+ return _dom_element_remove_attr(element, attrs, localname);
}
/**
@@ -805,25 +612,28 @@ dom_exception _dom_element_get_attribute_node_ns(struct dom_element *element,
struct dom_string *namespace, struct dom_string *localname,
struct dom_attr **result)
{
- struct dom_node_internal *a = (struct dom_node_internal *)
- element->attributes;
-
- /** \todo ensure XML feature is supported */
+ lwc_string *str;
+ dom_exception err;
+ struct dom_hash_table *attrs;
- /* Search attributes, looking for namespace/localname */
- for (; a != NULL; a = a->next) {
- if (((namespace == NULL && a->namespace == NULL) ||
- (namespace != NULL &&
- dom_string_cmp(a->namespace, namespace) == 0)) &&
- dom_string_cmp(a->name, localname) == 0)
- break;
+ if (namespace == NULL) {
+ return _dom_element_get_attribute_node(element, localname,
+ result);
}
- if (a != NULL)
- dom_node_ref(a);
- *result = (struct dom_attr *) a;
+ err = _dom_node_get_intern_string(&element->base, namespace, &str);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ attrs = (struct dom_hash_table *) _dom_hash_get(element->ns_attributes,
+ str);
+ /* The element has no such namespace */
+ if (attrs == NULL) {
+ *result = NULL;
+ return DOM_NO_ERR;
+ }
- return DOM_NO_ERR;
+ return _dom_element_get_attr_node(element, attrs, localname, result);
}
/**
@@ -851,84 +661,47 @@ dom_exception _dom_element_get_attribute_node_ns(struct dom_element *element,
dom_exception _dom_element_set_attribute_node_ns(struct dom_element *element,
struct dom_attr *attr, struct dom_attr **result)
{
- struct dom_node_internal *e = (struct dom_node_internal *) element;
- struct dom_node_internal *a = (struct dom_node_internal *) attr;
- struct dom_attr *prev = NULL;
-
- /** \todo ensure XML feature is supported */
-
- /* Ensure element and attribute belong to the same document */
- if (e->owner != a->owner)
- return DOM_WRONG_DOCUMENT_ERR;
-
- /* Ensure element can be written to */
- if (_dom_node_readonly(e))
- return DOM_NO_MODIFICATION_ALLOWED_ERR;
-
- /* Ensure attribute isn't attached to another element */
- if (a->parent != NULL && a->parent != e)
- return DOM_INUSE_ATTRIBUTE_ERR;
-
- /* Attach attr to element, if not already attached */
- if (a->parent == NULL) {
-
- /* Search for existing attribute with same namespace/localname */
- prev = element->attributes;
- while (prev != NULL) {
- struct dom_node_internal *p =
- (struct dom_node_internal *) prev;
-
- if (((a->namespace == NULL && p->namespace == NULL) ||
- (a->namespace != NULL &&
- dom_string_cmp(a->namespace,
- p->namespace) == 0)) &&
- dom_string_cmp(a->name, p->name) == 0)
- break;
-
- prev = (struct dom_attr *) p->next;
- }
-
- a->parent = e;
-
- if (prev != NULL) {
- /* Found an existing attribute, so replace it */
- struct dom_node_internal *p =
- (struct dom_node_internal *) prev;
-
- a->previous = p->previous;
- a->next = p->next;
-
- if (a->previous != NULL)
- a->previous->next = a;
- else
- element->attributes = attr;
+ lwc_string *str;
+ dom_exception err;
+ struct dom_hash_table *attrs;
+ bool added;
+ dom_string *namespace;
- if (a->next != NULL)
- a->next->previous = a;
+ err = dom_node_get_namespace(attr, (void *) &namespace);
+ if (err != DOM_NO_ERR)
+ return err;
- /* Invalidate existing attribute's location info */
- p->next = NULL;
- p->previous = NULL;
- p->parent = NULL;
- } else {
- /* No existing attribute, so insert at front of list */
- a->previous = NULL;
- a->next = (struct dom_node_internal *)
- element->attributes;
+ if (namespace == NULL)
+ return _dom_element_set_attribute_node(element, attr, result);
- if (a->next != NULL)
- a->next->previous = a;
+ err = _dom_node_get_intern_string(&element->base, namespace, &str);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ attrs = (struct dom_hash_table *) _dom_hash_get(element->ns_attributes,
+ str);
+ /* The element has no such namespace */
+ if (attrs == NULL) {
+ dom_document *doc;
+ doc = dom_node_get_owner(element);
+ assert(doc != NULL);
+ err = _dom_document_create_hashtable(doc, CHAINS_NS_ATTRIBUTES,
+ _dom_element_hash_lwcstring, &attrs);
+ if (err != DOM_NO_ERR)
+ return err;
- element->attributes = attr;
- }
+ added = _dom_hash_add(element->ns_attributes, str, attrs,
+ false);
+ if (added == false)
+ return DOM_NO_MEM_ERR;
}
- if (prev != NULL)
- dom_node_ref((struct dom_node *) prev);
-
- *result = prev;
+ dom_string *localname;
+ err = dom_node_get_local_name(attr, (void *) &localname);
+ if (err != DOM_NO_ERR)
+ return err;
- return DOM_NO_ERR;
+ return _dom_element_set_attr_node(element, attrs, attr, result);
}
/**
@@ -953,11 +726,40 @@ dom_exception _dom_element_get_elements_by_tag_name_ns(
struct dom_element *element, struct dom_string *namespace,
struct dom_string *localname, struct dom_nodelist **result)
{
+ dom_document *doc;
+ dom_exception err;
+ doc = element->base.owner;
+
/** \todo ensure XML feature is supported */
- return dom_document_get_nodelist(element->base.owner,
- (struct dom_node_internal *) element, NULL,
- namespace, localname, result);
+ /* Get the interned string from the dom_string */
+ assert(doc->context != NULL);
+ lwc_string *l = NULL, *n = NULL;
+ if (localname != NULL) {
+ err = _dom_string_intern(localname, doc->context, &l);
+ if (err != DOM_NO_ERR)
+ return err;
+ }
+ if (namespace != NULL) {
+ err = _dom_string_intern(namespace, doc->context, &n);
+ if (err != DOM_NO_ERR) {
+ lwc_context_string_unref(doc->context, l);
+
+ return err;
+ }
+ }
+
+ err = _dom_document_get_nodelist(element->base.owner,
+ DOM_NODELIST_BY_NAMESPACE,
+ (struct dom_node_internal *) element, NULL, n, l,
+ result);
+
+ if (localname != NULL)
+ lwc_context_string_unref(doc->context, l);
+ if (namespace != NULL)
+ lwc_context_string_unref(doc->context, n);
+
+ return err;
}
/**
@@ -971,18 +773,8 @@ dom_exception _dom_element_get_elements_by_tag_name_ns(
dom_exception _dom_element_has_attribute(struct dom_element *element,
struct dom_string *name, bool *result)
{
- struct dom_node_internal *a = (struct dom_node_internal *)
- element->attributes;
-
- /* Search attributes, looking for name */
- for (; a != NULL; a = a->next) {
- if (dom_string_cmp(a->name, name) == 0)
- break;
- }
-
- *result = (a != NULL);
-
- return DOM_NO_ERR;
+ return _dom_element_has_attr(element, element->attributes, name,
+ result);
}
/**
@@ -1003,23 +795,26 @@ dom_exception _dom_element_has_attribute_ns(struct dom_element *element,
struct dom_string *namespace, struct dom_string *localname,
bool *result)
{
- struct dom_node_internal *a = (struct dom_node_internal *)
- element->attributes;
+ lwc_string *str;
+ dom_exception err;
+ struct dom_hash_table *attrs;
- /** \todo ensure XML feature is supported */
+ if (namespace == NULL)
+ return _dom_element_has_attribute(element, localname, result);
- /* Search attributes, looking for namespace/localname */
- for (; a != NULL; a = a->next) {
- if (((namespace == NULL && a->namespace == NULL) ||
- (namespace != NULL &&
- dom_string_cmp(a->namespace, namespace) == 0)) &&
- dom_string_cmp(a->name, localname) == 0)
- break;
+ err = _dom_node_get_intern_string(&element->base, namespace, &str);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ attrs = (struct dom_hash_table *) _dom_hash_get(element->ns_attributes,
+ str);
+ /* The element has no such namespace */
+ if (attrs == NULL) {
+ *result = false;
+ return DOM_NO_ERR;
}
- *result = (a != NULL);
-
- return DOM_NO_ERR;
+ return _dom_element_has_attr(element, attrs, localname, result);
}
/**
@@ -1052,15 +847,16 @@ dom_exception _dom_element_get_schema_type_info(struct dom_element *element,
* DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
* DOM_NOT_FOUND_ERR if the specified node is not an
* attribute of ::element.
+ *
+ * @note: The DOM spec does not say: how to deal with when there are two or
+ * more isId attribute nodes. Here, the implementation just maintain only
+ * one such attribute node.
*/
dom_exception _dom_element_set_id_attribute(struct dom_element *element,
struct dom_string *name, bool is_id)
{
- UNUSED(element);
- UNUSED(name);
- UNUSED(is_id);
-
- return DOM_NOT_SUPPORTED_ERR;
+ return _dom_element_set_id_attr(element, element->attributes, name,
+ is_id);
}
/**
@@ -1079,12 +875,28 @@ dom_exception _dom_element_set_id_attribute_ns(struct dom_element *element,
struct dom_string *namespace, struct dom_string *localname,
bool is_id)
{
- UNUSED(element);
- UNUSED(namespace);
- UNUSED(localname);
- UNUSED(is_id);
+ struct dom_hash_table *hs;
+ dom_exception err;
+ lwc_string *ns;
- return DOM_NOT_SUPPORTED_ERR;
+ if (namespace == NULL)
+ return _dom_element_set_id_attribute(element, localname, is_id);
+
+ err = _dom_node_get_intern_string(&element->base, namespace, &ns);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ hs = (struct dom_hash_table *) _dom_hash_get(element->ns_attributes,
+ ns);
+ assert(hs != NULL);
+
+ err = _dom_element_set_id_attr(element, hs, localname, is_id);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ element->id_ns = ns;
+
+ return DOM_NO_ERR;
}
/**
@@ -1101,59 +913,1078 @@ dom_exception _dom_element_set_id_attribute_ns(struct dom_element *element,
dom_exception _dom_element_set_id_attribute_node(struct dom_element *element,
struct dom_attr *id_attr, bool is_id)
{
- UNUSED(element);
- UNUSED(id_attr);
- UNUSED(is_id);
+ struct dom_hash_table *hs;
+ dom_exception err;
+ lwc_string *ns;
+ dom_string *namespace;
+ dom_string *localname;
- return DOM_NOT_SUPPORTED_ERR;
+ err = dom_node_get_namespace(id_attr, &namespace);
+ if (err != DOM_NO_ERR)
+ return err;
+ err = dom_node_get_local_name(id_attr, &localname);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ err = _dom_node_get_intern_string(&element->base, namespace, &ns);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ hs = (struct dom_hash_table *) _dom_hash_get(element->ns_attributes,
+ ns);
+ assert(hs != NULL);
+
+ err = _dom_element_set_id_attr(element, hs, localname, is_id);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ element->id_ns = ns;
+
+ return DOM_NO_ERR;
+
+}
+
+/*------------- The overload virtual functions ------------------------*/
+
+/* Overload function of Node, please refer src/core/node.c for detail */
+dom_exception _dom_element_get_attributes(dom_node_internal *node,
+ struct dom_namednodemap **result)
+{
+ dom_exception err;
+ dom_document *doc;
+
+ doc = dom_node_get_owner(node);
+ assert(doc != NULL);
+
+ err = _dom_namednodemap_create(doc, node, &attributes_opt, result);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ dom_node_ref(node);
+
+ return DOM_NO_ERR;
}
-/* */
-/*----------------------------------------------------------------------------*/
-/* */
+/* Overload function of Node, please refer src/core/node.c for detail */
+dom_exception _dom_element_has_attributes(dom_node_internal *node, bool *result)
+{
+ UNUSED(node);
+ *result = true;
+
+ return DOM_NO_ERR;
+}
+
+/* For the following namespace related algorithm take a look at:
+ * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/namespaces-algorithms.html
+ */
/**
- * Retrieve a map of attributes associated with an Element
+ * Look up the prefix which matches the namespace.
*
- * \param element The element to retrieve the attributes of
- * \param result Pointer to location to receive attribute map
- * \return DOM_NO_ERR.
+ * \param node The current Node in which we search for
+ * \param namespace The namespace for which we search a prefix
+ * \param result The returned prefix
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ */
+dom_exception _dom_element_lookup_prefix(dom_node_internal *node,
+ struct dom_string *namespace, struct dom_string **result)
+{
+ struct dom_element *owner;
+ dom_exception err;
+
+ err = dom_attr_get_owner_element(node, &owner);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ if (owner == NULL) {
+ *result = NULL;
+ return DOM_NO_ERR;
+ }
+
+ return dom_node_lookup_prefix(owner, namespace, result);
+}
+
+/**
+ * Test whether certain namespace is the default namespace of some node.
*
- * The returned NamedNodeMap will be referenced. It is the responsibility
- * of the caller to unref the map once it has finished with it.
+ * \param node The Node to test
+ * \param namespace The namespace to test
+ * \param result true is the namespace is default namespace
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
*/
-dom_exception dom_element_get_attributes(struct dom_element *element,
- struct dom_namednodemap **result)
+dom_exception _dom_element_is_default_namespace(dom_node_internal *node,
+ struct dom_string *namespace, bool *result)
{
- return dom_document_get_namednodemap(element->base.owner,
- (struct dom_node_internal *) element,
- DOM_ATTRIBUTE_NODE, result);
+ struct dom_element *ele = (struct dom_element *) node;
+ lwc_string *ns;
+ dom_string *value;
+ dom_document *doc = node->owner;
+ lwc_context *ctx;
+ dom_exception err;
+
+ assert(doc != NULL);
+ err = _dom_node_get_intern_string(node, namespace, &ns);
+ if (err != DOM_NO_ERR) {
+ return err;
+ }
+ ctx = _dom_document_get_intern_context(doc);
+ assert(ctx != NULL);
+ if (node->prefix == NULL) {
+ lwc_context_string_isequal(ctx, node->namespace, ns, result);
+ lwc_context_string_unref(ctx, ns);
+ return DOM_NO_ERR;
+ }
+
+ bool has;
+ dom_string *xmlns = _dom_namespace_get_xmlns_prefix();
+ err = dom_element_has_attribute(ele, xmlns, &has);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ if (has == true) {
+ return dom_element_get_attribute(ele, xmlns, &value);
+ }
+
+ lwc_string *ns2;
+ err = _dom_node_get_intern_string(node, value, &ns2);
+ if (err != DOM_NO_ERR) {
+ return err;
+ }
+
+ if (ns2 != NULL) {
+ lwc_context_string_isequal(ctx, ns2, ns, result);
+ lwc_context_string_unref(ctx, ns);
+ lwc_context_string_unref(ctx, ns2);
+ dom_string_unref(value);
+ return DOM_NO_ERR;
+ }
+
+
+ return dom_node_is_default_namespace(node->parent, namespace, result);
}
/**
- * Determine if an element has any attributes
+ * Look up the namespace with certain prefix.
*
- * \param element Element to inspect
- * \param result Pointer to location to receive result
+ * \param node The current node in which we search for the prefix
+ * \param prefix The prefix to search
+ * \param result The result namespace if found
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ */
+dom_exception _dom_element_lookup_namespace(dom_node_internal *node,
+ struct dom_string *prefix, struct dom_string **result)
+{
+ lwc_string *pf;
+ dom_exception err;
+
+ err = _dom_node_get_intern_string(node, prefix, &pf);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ /* To some extent, directly compare the two lwc_string pointer
+ * is better */
+ if (node->namespace != NULL && node->prefix == pf) {
+ assert(node->owner != NULL);
+ return _dom_document_create_string_from_lwcstring(node->owner,
+ pf, result);
+ }
+
+ bool has;
+ dom_string *xmlns = _dom_namespace_get_xmlns_prefix();
+ err = dom_element_has_attribute_ns(node,
+ dom_namespaces[DOM_NAMESPACE_XMLNS], prefix, &has);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ if (has == true)
+ return dom_element_get_attribute_ns(node,
+ dom_namespaces[DOM_NAMESPACE_XMLNS], prefix,
+ result);
+
+ err = dom_element_has_attribute(node, xmlns, &has);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ if (has == true) {
+ return dom_element_get_attribute(node, xmlns, result);
+ }
+
+ return dom_node_lookup_namespace(node->parent, prefix, result);
+}
+
+
+/*----------------------------------------------------------------------*/
+/* The protected virtual functions */
+
+/* The destroy virtual function of dom_element */
+void __dom_element_destroy(struct dom_node_internal *node)
+{
+ struct dom_document *doc = dom_node_get_owner(node);
+
+ _dom_element_destroy(doc, (struct dom_element *) node);
+}
+
+/* The memory allocator of this class */
+dom_exception _dom_element_alloc(dom_document *doc, struct dom_node_internal *n,
+ struct dom_node_internal **ret)
+{
+ dom_element *e;
+ UNUSED(n);
+
+ e = _dom_document_alloc(doc, NULL, sizeof(struct dom_element));
+ if (e == NULL)
+ return DOM_NO_MEM_ERR;
+
+ *ret = (dom_node_internal *) e;
+ dom_node_set_owner(*ret, doc);
+
+ return DOM_NO_ERR;
+}
+
+/* TODO: How to deal with default attribue:
+ *
+ * Ask a language binding for default attributes.
+ *
+ * So, when we copy a element we copy all its attributes because they
+ * are all specified. For the methods like importNode and adoptNode,
+ * this will make _dom_element_copy can be used in them.
+ */
+dom_exception _dom_element_copy(struct dom_node_internal *new,
+ struct dom_node_internal *old)
+{
+ dom_element *ne = (dom_element *) new;
+ dom_element *oe = (dom_element *) old;
+ dom_document *od, *nd;
+ struct dom_hash_table *ht;
+ lwc_context *oc, *nc;
+ dom_exception err;
+
+ err = _dom_node_copy(new, old);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ od = dom_node_get_owner(old);
+ nd = dom_node_get_owner(new);
+ assert(od != NULL);
+ assert(nd != NULL);
+
+ oc = _dom_document_get_intern_context(od);
+ nc = _dom_document_get_intern_context(nd);
+ assert(oc != NULL);
+ assert(nc != NULL);
+
+ dom_alloc alloc;
+ void *pw;
+ _dom_document_get_allocator(nd, &alloc, &pw);
+
+ /* Copy the hash tables */
+ ht = _dom_hash_clone(oe->attributes, alloc, pw, _key, nc,
+ _value, nd);
+ if (ht == NULL)
+ return DOM_NO_MEM_ERR;
+ ne->attributes = ht;
+
+ ht = _dom_hash_clone(oe->ns_attributes, alloc, pw, _key, nc,
+ _nsattributes, nd);
+ if (ht == NULL)
+ return DOM_NO_MEM_ERR;
+ ne->ns_attributes = ht;
+
+ /* TODO: deal with dom_type_info, it get no definition ! */
+
+ return DOM_NO_ERR;
+}
+
+
+
+/*--------------------------------------------------------------------------*/
+
+/* Helper functions */
+
+/**
+ * The internal helper function for getAttribute/getAttributeNS.
+ *
+ * \param element The element
+ * \param hs The hash table contains the attributes
+ * \param name The name of the attribute
+ * \param value The value of the attribute
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ */
+dom_exception _dom_element_get_attr(struct dom_element *element,
+ struct dom_hash_table *hs, struct dom_string *name,
+ struct dom_string **value)
+{
+ void *a;
+ dom_exception err;
+ lwc_string *str;
+
+ /* Looking for name */
+ err = _dom_node_get_intern_string(&element->base, name, &str);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ a = _dom_hash_get(hs, str);
+
+ /* Fill in value */
+ if (a == NULL) {
+ *value = NULL;
+ } else {
+ dom_attr_get_value(((struct dom_attr *) a), value);
+ }
+
+ return DOM_NO_ERR;
+}
+
+/**
+ * The internal helper function for setAttribute and setAttributeNS.
+ *
+ * \param element The element
+ * \param hs The attributes' hash table
+ * \param name The name of the new attribute
+ * \param value The value of the new attribute
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ */
+dom_exception _dom_element_set_attr(struct dom_element *element,
+ struct dom_hash_table *hs, struct dom_string *name,
+ struct dom_string *value)
+{
+ void *a;
+ dom_exception err;
+ lwc_string *str;
+ bool added;
+ dom_node_internal *e = (dom_node_internal *) element;
+
+ if (_dom_validate_name(name) == false)
+ return DOM_INVALID_CHARACTER_ERR;
+
+ /* Ensure element can be written */
+ if (_dom_node_readonly(e))
+ return DOM_NO_MODIFICATION_ALLOWED_ERR;
+
+ /* Looking for name */
+ err = _dom_node_get_intern_string(&element->base, name, &str);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ a = _dom_hash_get(hs, str);
+
+ if (a != NULL) {
+ /* Found an existing attribute, so replace its value */
+ dom_exception err;
+
+ err = dom_attr_set_value((struct dom_attr *) a, value);
+ if (err != DOM_NO_ERR)
+ return err;
+ } else {
+ /* No existing attribute, so create one */
+ dom_exception err;
+ struct dom_attr *attr;
+
+ err = _dom_attr_create(e->owner, str, NULL, NULL, true, &attr);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ /* Set its value */
+ err = dom_attr_set_value(attr, value);
+ if (err != DOM_NO_ERR) {
+ dom_node_unref(attr);
+ return err;
+ }
+
+ added = _dom_hash_add(hs, str, attr, false);
+ if (added == false) {
+ /* If we failed at this step, there must be no memory */
+ dom_node_unref(attr);
+ return DOM_NO_MEM_ERR;
+ }
+
+ dom_node_set_parent(attr, element);
+ dom_node_unref(attr);
+ dom_node_remove_pending(attr);
+ }
+
+ return DOM_NO_ERR;
+}
+
+/**
+ * Remove an attribute from an element by name
+ *
+ * \param element The element to remove attribute from
+ * \param name The name of the attribute to remove
+ * \return DOM_NO_ERR on success,
+ * DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly.
+ */
+dom_exception _dom_element_remove_attr(struct dom_element *element,
+ struct dom_hash_table *hs, struct dom_string *name)
+{
+ void *a;
+ dom_exception err;
+ lwc_string *str;
+ dom_node_internal *e = (dom_node_internal *) element;
+
+ /* Ensure element can be written to */
+ if (_dom_node_readonly(e))
+ return DOM_NO_MODIFICATION_ALLOWED_ERR;
+
+ /* Looking for name */
+ err = _dom_node_get_intern_string(&element->base, name, &str);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ a = (dom_node_internal *) _dom_hash_del(hs, str);
+
+ /* Detach attr node from list */
+ if (a != NULL) {
+ /* And destroy attr */
+ dom_node_set_parent(a, NULL);
+ dom_node_try_destroy(a);
+ }
+
+ /** \todo defaulted attribute handling */
+
+ return DOM_NO_ERR;
+}
+
+/**
+ * Retrieve an attribute node from an element by name
+ *
+ * \param element The element to retrieve attribute node from
+ * \param name The attribute's name
+ * \param result Pointer to location to receive attribute node
* \return DOM_NO_ERR.
+ *
+ * The returned node will have its reference count increased. It is
+ * the responsibility of the caller to unref the node once it has
+ * finished with it.
+ */
+dom_exception _dom_element_get_attr_node(struct dom_element *element,
+ struct dom_hash_table *hs, struct dom_string *name,
+ struct dom_attr **result)
+{
+ void *a;
+ dom_exception err;
+ lwc_string *str;
+
+ /* Looking for name */
+ err = _dom_node_get_intern_string(&element->base, name, &str);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ a = _dom_hash_get(hs, str);
+
+ /* Fill in value */
+ if (a == NULL) {
+ *result = NULL;
+ } else {
+ *result = (dom_attr *) a;
+ dom_node_ref(*result);
+ }
+
+ return DOM_NO_ERR;
+}
+
+/**
+ * Set an attribute node on an element, replacing existing node, if present
+ *
+ * \param element The element to add a node to
+ * \param attr The attribute node to add
+ * \param result Pointer to location to receive previous node
+ * \return DOM_NO_ERR on success,
+ * DOM_WRONG_DOCUMENT_ERR if ::attr does not belong to the
+ * same document as ::element,
+ * DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
+ * DOM_INUSE_ATTRIBUTE_ERR if ::attr is already an attribute
+ * of another Element node.
+ *
+ * The returned node will have its reference count increased. It is
+ * the responsibility of the caller to unref the node once it has
+ * finished with it.
*/
-dom_exception dom_element_has_attributes(struct dom_element *element,
+dom_exception _dom_element_set_attr_node(struct dom_element *element,
+ struct dom_hash_table *hs, struct dom_attr *attr,
+ struct dom_attr **result)
+{
+ dom_exception err;
+ lwc_string *str = NULL;
+ dom_string *name = NULL;
+ bool added;
+ dom_node_internal *e = (dom_node_internal *) element;
+ dom_node_internal *a = (dom_node_internal *) attr;
+
+ /** \todo validate name */
+
+ /* Ensure element and attribute belong to the same document */
+ if (e->owner != a->owner)
+ return DOM_WRONG_DOCUMENT_ERR;
+
+ /* Ensure element can be written to */
+ if (_dom_node_readonly(e))
+ return DOM_NO_MODIFICATION_ALLOWED_ERR;
+
+ /* Ensure attribute isn't attached to another element */
+ if (a->parent != NULL && a->parent != e)
+ return DOM_INUSE_ATTRIBUTE_ERR;
+
+ err = dom_node_get_local_name(attr, &name);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ /* Looking for name */
+ err = _dom_node_get_intern_string(&element->base, name, &str);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ a = _dom_hash_del(hs, str);
+
+ *result = NULL;
+ if (a != NULL) {
+ dom_node_ref(a);
+ *result = (dom_attr *) a;
+ dom_node_set_parent(a, NULL);
+ dom_node_mark_pending(a);
+ }
+
+ added = _dom_hash_add(hs, str, attr, false);
+ if (added == false) {
+ /* If we failed at this step, there must be no memory */
+ return DOM_NO_MEM_ERR;
+ }
+ dom_node_set_parent(attr, element);
+ dom_node_remove_pending(attr);
+
+ /* Cleanup */
+ if (name != NULL)
+ dom_string_unref(name);
+
+ return DOM_NO_ERR;
+}
+
+/**
+ * Remove an attribute node from an element
+ *
+ * \param element The element to remove attribute node from
+ * \param attr The attribute node to remove
+ * \param result Pointer to location to receive attribute node
+ * \return DOM_NO_ERR on success,
+ * DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
+ * DOM_NOT_FOUND_ERR if ::attr is not an attribute of
+ * ::element.
+ *
+ * The returned node will have its reference count increased. It is
+ * the responsibility of the caller to unref the node once it has
+ * finished with it.
+ */
+dom_exception _dom_element_remove_attr_node(struct dom_element *element,
+ struct dom_hash_table *hs, struct dom_attr *attr,
+ struct dom_attr **result)
+{
+ void *a;
+ dom_exception err;
+ lwc_string *str;
+ dom_string *name;
+ dom_node_internal *e = (dom_node_internal *) element;
+
+ /* Ensure element can be written to */
+ if (_dom_node_readonly(e))
+ return DOM_NO_MODIFICATION_ALLOWED_ERR;
+
+ err = dom_node_get_node_name(attr, &name);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ /* Looking for name */
+ err = _dom_node_get_intern_string(&element->base, name, &str);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ a = _dom_hash_del(hs, str);
+
+ /* Now, cleaup the dom_string and lwc_string */
+ dom_string_unref(name);
+ _dom_node_unref_intern_string(&element->base, str);
+
+ /** \todo defaulted attribute handling */
+
+ if (a == NULL || a != (void *) attr) {
+ return DOM_NOT_FOUND_ERR;
+ }
+
+ /* When a Node is removed, it should be destroy. When its refcnt is not
+ * zero, it will be added to the document's deletion pending list.
+ * When a Node is removed, its parent should be NULL, but its owner
+ * should remain to be the document.
+ */
+ dom_node_ref(a);
+ *result = (dom_attr *) a;
+ dom_node_set_parent(a, NULL);
+ dom_node_mark_pending(a);
+
+ return DOM_NO_ERR;
+}
+
+/**
+ * Test whether certain attribute is inside the hash table
+ *
+ * \param element The element
+ * \param hs The hash table contains the attributes
+ * \param name The attribute's name
+ * \param result The return value
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ */
+dom_exception _dom_element_has_attr(struct dom_element *element,
+ struct dom_hash_table *hs, struct dom_string *name,
bool *result)
{
- *result = (element->attributes != NULL);
+ void *a;
+ dom_exception err;
+ lwc_string *str;
+
+ /* Looking for name */
+ err = _dom_node_get_intern_string(&element->base, name, &str);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ a = _dom_hash_get(hs, str);
+
+ /* Fill in value */
+ if (a == NULL) {
+ *result = false;
+ } else {
+ *result = true;
+ }
return DOM_NO_ERR;
}
/**
- * Retrieve a pointer to the first attribute attached to an element
+ * (Un)set an attribute Node as a ID.
*
- * \param element The element to retrieve the first attribute from
- * \return Pointer to first attribute, or NULL if none.
+ * \param element The element contains the attribute
+ * \param hs The hash table which contains the attribute node
+ * \param name The name of the attribute
+ * \param is_id true for set the node as a ID attribute, false unset it
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
*/
-struct dom_node_internal *dom_element_get_first_attribute(
- struct dom_element *element)
+dom_exception _dom_element_set_id_attr(struct dom_element *element,
+ struct dom_hash_table *hs, struct dom_string *name, bool is_id)
+{
+ dom_attr *attr;
+ lwc_string *str;
+ dom_exception err;
+ struct dom_hash_table *oh;
+
+ /* Looking for name */
+ err = _dom_node_get_intern_string(&element->base, name, &str);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ attr = (dom_attr *) _dom_hash_get(hs, str);
+ if (attr == NULL)
+ return DOM_NOT_FOUND_ERR;
+
+ if (is_id == true) {
+ /* Firstly, clear the previous id attribute if there is one */
+ if (element->id_ns != NULL) {
+ assert(element->id_name != NULL);
+ oh = (struct dom_hash_table *) _dom_hash_get(
+ element->ns_attributes, element->id_ns);
+ } else {
+ oh = element->attributes;
+ }
+ assert(oh != NULL);
+
+ if (element->id_name != NULL) {
+ attr = (dom_attr *) _dom_hash_get(oh, element->id_name);
+ assert(attr != NULL);
+ _dom_attr_set_isid(attr, false);
+ }
+ }
+
+ _dom_attr_set_isid(attr, is_id);
+
+ element->id_name = str;
+
+ return DOM_NO_ERR;
+}
+
+/**
+ * Get the ID string of the element
+ *
+ * \param ele The element
+ * \param id The ID of this element
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ */
+dom_exception _dom_element_get_id(struct dom_element *ele, lwc_string **id)
{
- return (struct dom_node_internal *) element->attributes;
+ dom_exception err;
+ dom_string *ret = NULL;
+
+ *id = NULL;
+
+ if (ele->id_ns != NULL && ele->id_name != NULL) {
+ /* There is user specific ID attribute */
+ dom_document *doc;
+ doc = dom_node_get_owner(ele);
+ assert(doc != NULL);
+
+ dom_string *namespace, *name;
+ err = _dom_document_create_string_from_lwcstring(doc,
+ ele->id_ns, &namespace);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ err = _dom_document_create_string_from_lwcstring(doc,
+ ele->id_name, &name);
+ if (err != DOM_NO_ERR) {
+ dom_string_unref(namespace);
+ return err;
+ }
+
+ err = _dom_element_get_attribute_ns(ele, namespace, name, &ret);
+ if (err != DOM_NO_ERR) {
+ dom_string_unref(namespace);
+ dom_string_unref(name);
+ return err;
+ }
+
+ dom_string_unref(namespace);
+ dom_string_unref(name);
+
+ err = _dom_node_get_intern_string((dom_node_internal *) ele,
+ ret, id);
+ dom_string_unref(ret);
+ return err;
+ }
+
+ dom_document *doc;
+ doc = dom_node_get_owner(ele);
+ assert(doc != NULL);
+ dom_string *name;
+
+ if (ele->id_name != NULL) {
+ err = _dom_document_create_string_from_lwcstring(doc,
+ ele->id_name, &name);
+ if (err != DOM_NO_ERR) {
+ return err;
+ }
+ } else {
+ lwc_string *id_name = _dom_document_get_id_name(doc);
+ if (id_name == NULL) {
+ /* No ID attribute at all, just return NULL */
+ *id = NULL;
+ return DOM_NO_ERR;
+ }
+ err = _dom_document_create_string_from_lwcstring(doc, id_name,
+ &name);
+ if (err != DOM_NO_ERR) {
+ return err;
+ }
+ }
+
+ err = _dom_element_get_attribute(ele, name, &ret);
+ if (err != DOM_NO_ERR) {
+ dom_string_unref(name);
+ return err;
+ }
+
+ dom_string_unref(name);
+
+ if (ret != NULL) {
+ err = _dom_node_get_intern_string((dom_node_internal *) ele,
+ ret, id);
+ dom_string_unref(ret);
+ } else {
+ *id = NULL;
+ }
+
+ return err;
+}
+
+
+/* The hash function for attributes and id tables */
+unsigned int _dom_element_hash_lwcstring(void *key)
+{
+ lwc_string *lstr = (lwc_string *) key;
+
+ return lwc_string_hash_value(lstr);
+}
+
+/*-------------- The dom_namednodemap functions -------------------------*/
+
+/* Implementation function for NamedNodeMap, see core/namednodemap.h for
+ * details */
+dom_exception attributes_get_length(void *priv,
+ unsigned long *length)
+{
+ unsigned int ret = 0;
+ unsigned int c1, *c2 = NULL;
+ void *key, *value;
+ dom_element *e = (dom_element *) priv;
+
+ ret += _dom_hash_get_length(e->attributes);
+ while( (key = _dom_hash_iterate(e->ns_attributes, &c1, &c2)) != NULL) {
+ value = _dom_hash_get(e->ns_attributes, key);
+ if (value != NULL) {
+ ret += _dom_hash_get_length(
+ (struct dom_hash_table *) value);
+ }
+ }
+
+ *length = ret;
+ return DOM_NO_ERR;
+}
+
+/* Implementation function for NamedNodeMap, see core/namednodemap.h for
+ * details */
+dom_exception attributes_get_named_item(void *priv,
+ struct dom_string *name, struct dom_node **node)
+{
+ dom_element *e = (dom_element *) priv;
+
+ return _dom_element_get_attribute_node(e, name, (dom_attr **) node);
+}
+
+/* Implementation function for NamedNodeMap, see core/namednodemap.h for
+ * details */
+dom_exception attributes_set_named_item(void *priv,
+ struct dom_node *arg, struct dom_node **node)
+{
+ dom_element *e = (dom_element *) priv;
+ dom_node_internal *n = (dom_node_internal *) arg;
+
+ if (n->type != DOM_ATTRIBUTE_NODE)
+ return DOM_HIERARCHY_REQUEST_ERR;
+
+ return _dom_element_set_attribute_node(e, (dom_attr *) arg,
+ (dom_attr **) node);
+}
+
+/* Implementation function for NamedNodeMap, see core/namednodemap.h for
+ * details */
+dom_exception attributes_remove_named_item(
+ void *priv, struct dom_string *name,
+ struct dom_node **node)
+{
+ dom_element *e = (dom_element *) priv;
+ dom_exception err;
+
+ err = _dom_element_get_attribute_node(e, name, (dom_attr **) node);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ if (*node == NULL) {
+ return DOM_NOT_FOUND_ERR;
+ }
+
+ return _dom_element_remove_attribute(e, name);
+}
+
+/* Implementation function for NamedNodeMap, see core/namednodemap.h for
+ * details */
+dom_exception attributes_item(void *priv,
+ unsigned long index, struct dom_node **node)
+{
+ struct dom_hash_table *ht = NULL;
+ unsigned int num = index + 1;
+ unsigned int len;
+ dom_element *e = (dom_element *) priv;
+ void *key, *value;
+ unsigned int c1, *c2 = NULL;
+
+ len = _dom_hash_get_length(e->attributes);
+ if (num <= len) {
+ ht = e->attributes;
+ } else {
+ num -= len;
+ }
+
+ while( (key = _dom_hash_iterate(e->ns_attributes, &c1, &c2)) != NULL) {
+ value = _dom_hash_get(e->ns_attributes, key);
+ if (value != NULL) {
+ len = _dom_hash_get_length(
+ (struct dom_hash_table *) value);
+ if (num <= len) {
+ ht = (struct dom_hash_table *) value;
+ break;
+ } else {
+ num -= len;
+ }
+ }
+ }
+
+ *node = NULL;
+ c2 = NULL;
+ if (ht != NULL)
+ {
+ while( (key = _dom_hash_iterate(ht, &c1, &c2)) != NULL) {
+ value = _dom_hash_get(ht, key);
+ if (--num == 0) {
+ *node = (dom_node *) value;
+ break;
+ }
+ }
+ }
+
+ if (*node != NULL)
+ dom_node_ref(*node);
+
+ return DOM_NO_ERR;
+}
+
+/* Implementation function for NamedNodeMap, see core/namednodemap.h for
+ * details */
+dom_exception attributes_get_named_item_ns(
+ void *priv, struct dom_string *namespace,
+ struct dom_string *localname, struct dom_node **node)
+{
+ dom_element *e = (dom_element *) priv;
+
+ return _dom_element_get_attribute_node_ns(e, namespace, localname,
+ (dom_attr **) node);
+}
+
+/* Implementation function for NamedNodeMap, see core/namednodemap.h for
+ * details */
+dom_exception attributes_set_named_item_ns(
+ void *priv, struct dom_node *arg,
+ struct dom_node **node)
+{
+ dom_element *e = (dom_element *) priv;
+ dom_node_internal *n = (dom_node_internal *) arg;
+
+ if (n->type != DOM_ATTRIBUTE_NODE)
+ return DOM_HIERARCHY_REQUEST_ERR;
+
+ return _dom_element_set_attribute_node_ns(e, (dom_attr *) arg,
+ (dom_attr **) node);
+}
+
+/* Implementation function for NamedNodeMap, see core/namednodemap.h for
+ * details */
+dom_exception attributes_remove_named_item_ns(
+ void *priv, struct dom_string *namespace,
+ struct dom_string *localname, struct dom_node **node)
+{
+ dom_element *e = (dom_element *) priv;
+ dom_exception err;
+
+ err = _dom_element_get_attribute_node_ns(e, namespace, localname,
+ (dom_attr **) node);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ if (*node == NULL) {
+ return DOM_NOT_FOUND_ERR;
+ }
+
+ return _dom_element_remove_attribute_ns(e, namespace, localname);
+}
+
+/* Implementation function for NamedNodeMap, see core/namednodemap.h for
+ * details */
+void attributes_destroy(void *priv)
+{
+ dom_element *e = (dom_element *) priv;
+
+ dom_node_unref(e);
+}
+
+/* Implementation function for NamedNodeMap, see core/namednodemap.h for
+ * details */
+bool attributes_equal(void *p1, void *p2)
+{
+ /* We have passed the pointer to this element as the private data,
+ * and here we just need to compare whether the two elements are
+ * equal
+ */
+ return p1 == p2;
+}
+/*------------------ End of namednodemap functions -----------------------*/
+
+/* The key_func of the hash table, see utils/hashtable.h for details */
+void *_key(void *key, void *key_pw, dom_alloc alloc, void *pw,
+ bool clone)
+{
+ assert(key != NULL);
+ assert(key_pw != NULL);
+
+ UNUSED(alloc);
+ UNUSED(pw);
+
+ if (clone == false) {
+ lwc_context_string_unref((lwc_context *) key_pw,
+ (lwc_string *) key);
+ return NULL;
+ } else {
+ lwc_error err;
+ lwc_string *ret;
+ const char *data = lwc_string_data((lwc_string *) key);
+ size_t len = lwc_string_length((lwc_string *) key);
+ err = lwc_context_intern((lwc_context *) key_pw, data, len,
+ &ret);
+ if (err != lwc_error_ok)
+ return NULL;
+
+ return ret;
+ }
+}
+
+/* The value_func of the hash table, see utils/hashtable.h for details */
+void *_value(void *value, void *value_pw, dom_alloc alloc,
+ void *pw, bool clone)
+{
+ assert(value != NULL);
+ assert(value_pw != NULL);
+
+ UNUSED(alloc);
+ UNUSED(pw);
+ UNUSED(value_pw);
+
+ if (clone == false) {
+ dom_node_internal *a = (dom_node_internal *) value;
+ a->parent = NULL;
+ dom_node_try_destroy(a);
+ return NULL;
+ } else {
+ dom_exception err;
+ dom_node *node;
+
+ err = dom_document_import_node((dom_document *) value_pw, value,
+ true, &node);
+ if (err != DOM_NO_ERR)
+ return NULL;
+
+ return node;
+ }
+}
+
+/* The value_func of the hash table, see utils/hashtable.h for details */
+void *_nsattributes(void *value, void *value_pw, dom_alloc alloc,
+ void *pw, bool clone)
+{
+ assert(value != NULL);
+ assert(value_pw != NULL);
+
+ UNUSED(alloc);
+ UNUSED(pw);
+
+ if (clone == false) {
+ _dom_hash_destroy((struct dom_hash_table *) value, _key,
+ value_pw, _value, value_pw);
+ return NULL;
+ } else {
+ dom_document *doc = (dom_document *) value_pw;
+ lwc_context *ctx = _dom_document_get_intern_context(doc);
+ assert(ctx != NULL);
+ dom_alloc alloc;
+ void *pw;
+ struct dom_hash_table *ret = NULL;
+ _dom_document_get_allocator(doc, &alloc, &pw);
+
+ ret = _dom_hash_clone((struct dom_hash_table *) value, alloc,
+ pw, _key, ctx, _value, doc);
+
+ return ret;
+ }
}
diff --git a/src/core/element.h b/src/core/element.h
index a05b8c0..f987fcd 100644
--- a/src/core/element.h
+++ b/src/core/element.h
@@ -19,6 +19,7 @@ struct dom_node;
struct dom_string;
struct dom_attr;
struct dom_type_info;
+struct dom_hash_table;
/**
* DOM element node
@@ -26,33 +27,31 @@ struct dom_type_info;
struct dom_element {
struct dom_node_internal base; /**< Base node */
- struct dom_attr *attributes; /**< Element attributes */
+ struct dom_hash_table *attributes; /**< Element attributes */
- struct dom_type_info *schema_type_info; /**< Type information */
-};
-
-dom_exception dom_element_create(struct dom_document *doc,
- struct dom_string *name, struct dom_string *namespace,
- struct dom_string *prefix, struct dom_element **result);
+ struct dom_hash_table *ns_attributes;
+ /**< Attributes with prefix */
-dom_exception dom_element_initialise(struct dom_element *el,
- struct dom_string *name, struct dom_string *namespace,
- struct dom_string *prefix, struct dom_element **result);
+ struct lwc_string_s *id_ns; /**< The id attribute's namespace */
-void dom_element_destroy(struct dom_document *doc,
- struct dom_element *element);
+ struct lwc_string_s *id_name; /**< The id attribute's name */
-void _dom_element_destroy(struct dom_node_internal *node);
+ struct dom_type_info *schema_type_info; /**< Type information */
+};
-dom_exception dom_element_get_attributes(struct dom_element *element,
- struct dom_namednodemap **result);
+dom_exception _dom_element_create(struct dom_document *doc,
+ struct lwc_string_s *name, struct lwc_string_s *namespace,
+ struct lwc_string_s *prefix, struct dom_element **result);
-dom_exception dom_element_has_attributes(struct dom_element *element,
- bool *result);
+dom_exception _dom_element_initialise(struct dom_element *el,
+ struct dom_document *doc, struct lwc_string_s *name,
+ struct lwc_string_s *namespace, struct lwc_string_s *prefix,
+ struct dom_element **result);
-struct dom_node_internal *dom_element_get_first_attribute(
+void _dom_element_destroy(struct dom_document *doc,
struct dom_element *element);
+
/* The virtual functions of dom_element */
dom_exception _dom_element_get_tag_name(struct dom_element *element,
struct dom_string **name);
@@ -68,8 +67,9 @@ dom_exception _dom_element_set_attribute_node(struct dom_element *element,
struct dom_attr *attr, struct dom_attr **result);
dom_exception _dom_element_remove_attribute_node(struct dom_element *element,
struct dom_attr *attr, struct dom_attr **result);
-dom_exception _dom_element_get_elements_by_tag_name(struct dom_element *element,
- struct dom_string *name, struct dom_nodelist **result);
+dom_exception _dom_element_get_elements_by_tag_name(
+ struct dom_element *element, struct dom_string *name,
+ struct dom_nodelist **result);
dom_exception _dom_element_get_attribute_ns(struct dom_element *element,
struct dom_string *namespace, struct dom_string *localname,
struct dom_string **value);
@@ -123,4 +123,72 @@ dom_exception _dom_element_set_id_attribute_node(struct dom_element *element,
_dom_element_set_id_attribute_ns, \
_dom_element_set_id_attribute_node
+/* Overloading dom_node functions */
+dom_exception _dom_element_get_attributes(dom_node_internal *node,
+ struct dom_namednodemap **result);
+dom_exception _dom_element_has_attributes(dom_node_internal *node,
+ bool *result);
+dom_exception _dom_element_normalize(dom_node_internal *node);
+dom_exception _dom_element_lookup_prefix(dom_node_internal *node,
+ struct dom_string *namespace, struct dom_string **result);
+dom_exception _dom_element_is_default_namespace(dom_node_internal *node,
+ struct dom_string *namespace, bool *result);
+dom_exception _dom_element_lookup_namespace(dom_node_internal *node,
+ struct dom_string *prefix, struct dom_string **result);
+#define DOM_NODE_VTABLE_ELEMENT \
+ _dom_node_get_node_name, \
+ _dom_node_get_node_value, \
+ _dom_node_set_node_value, \
+ _dom_node_get_node_type, \
+ _dom_node_get_parent_node, \
+ _dom_node_get_child_nodes, \
+ _dom_node_get_first_child, \
+ _dom_node_get_last_child, \
+ _dom_node_get_previous_sibling, \
+ _dom_node_get_next_sibling, \
+ _dom_element_get_attributes, /*overload*/\
+ _dom_node_get_owner_document, \
+ _dom_node_insert_before, \
+ _dom_node_replace_child, \
+ _dom_node_remove_child, \
+ _dom_node_append_child, \
+ _dom_node_has_child_nodes, \
+ _dom_node_clone_node, \
+ _dom_node_normalize, \
+ _dom_node_is_supported, \
+ _dom_node_get_namespace, \
+ _dom_node_get_prefix, \
+ _dom_node_set_prefix, \
+ _dom_node_get_local_name, \
+ _dom_element_has_attributes, /*overload*/\
+ _dom_node_get_base, \
+ _dom_node_compare_document_position, \
+ _dom_node_get_text_content, \
+ _dom_node_set_text_content, \
+ _dom_node_is_same, \
+ _dom_element_lookup_prefix, /*overload*/\
+ _dom_element_is_default_namespace, /*overload*/\
+ _dom_element_lookup_namespace, /*overload*/\
+ _dom_node_is_equal, \
+ _dom_node_get_feature, \
+ _dom_node_set_user_data, \
+ _dom_node_get_user_data
+
+
+/* The protected virtual function */
+void __dom_element_destroy(dom_node_internal *node);
+dom_exception _dom_element_alloc(struct dom_document *doc,
+ struct dom_node_internal *n, struct dom_node_internal **ret);
+dom_exception _dom_element_copy(struct dom_node_internal *new,
+ struct dom_node_internal *old);
+
+#define DOM_ELEMENT_PROTECT_VTABLE \
+ __dom_element_destroy, \
+ _dom_element_alloc, \
+ _dom_element_copy
+
+/* Helper functions*/
+dom_exception _dom_element_get_id(struct dom_element *ele,
+ struct lwc_string_s **id);
+
#endif
diff --git a/src/core/entity_ref.c b/src/core/entity_ref.c
index 2b90c79..c5b426c 100644
--- a/src/core/entity_ref.c
+++ b/src/core/entity_ref.c
@@ -3,8 +3,11 @@
* Licensed under the MIT License,
* http://www.opensource.org/licenses/mit-license.php
* Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
*/
+#include <libwapcaplet/libwapcaplet.h>
+
#include "core/document.h"
#include "core/entity_ref.h"
#include "core/node.h"
@@ -17,6 +20,14 @@ struct dom_entity_reference {
struct dom_node_internal base; /**< Base node */
};
+static struct dom_node_vtable er_vtable = {
+ DOM_NODE_VTABLE
+};
+
+static struct dom_node_protect_vtable er_protect_vtable = {
+ DOM_ER_PROTECT_VTABLE
+};
+
/**
* Create an entity reference
*
@@ -31,24 +42,27 @@ struct dom_entity_reference {
*
* The returned node will already be referenced.
*/
-dom_exception dom_entity_reference_create(struct dom_document *doc,
- struct dom_string *name, struct dom_string *value,
+dom_exception _dom_entity_reference_create(struct dom_document *doc,
+ struct lwc_string_s *name, struct dom_string *value,
struct dom_entity_reference **result)
{
struct dom_entity_reference *e;
dom_exception err;
/* Allocate the comment node */
- e = dom_document_alloc(doc, NULL,
+ e = _dom_document_alloc(doc, NULL,
sizeof(struct dom_entity_reference));
if (e == NULL)
return DOM_NO_MEM_ERR;
+ e->base.base.vtable = &er_vtable;
+ e->base.vtable = &er_protect_vtable;
+
/* And initialise the node */
- err = dom_node_initialise(&e->base, doc, DOM_ENTITY_REFERENCE_NODE,
- name, value, NULL, NULL);
+ err = _dom_entity_reference_initialise(&e->base, doc,
+ DOM_ENTITY_REFERENCE_NODE, name, value, NULL, NULL);
if (err != DOM_NO_ERR) {
- dom_document_alloc(doc, e, 0);
+ _dom_document_alloc(doc, e, 0);
return err;
}
@@ -65,52 +79,28 @@ dom_exception dom_entity_reference_create(struct dom_document *doc,
*
* The contents of ::entity will be destroyed and ::entity will be freed.
*/
-void dom_entity_reference_destroy(struct dom_document *doc,
+void _dom_entity_reference_destroy(struct dom_document *doc,
struct dom_entity_reference *entity)
{
- struct dom_node_internal *c, *d;
-
- /* Destroy children of this node */
- for (c = entity->base.first_child; c != NULL; c = d) {
- d = c->next;
-
- /* Detach child */
- c->parent = NULL;
-
- if (c->refcnt > 0) {
- /* Something is using this child */
-
- /** \todo add to list of nodes pending deletion */
-
- continue;
- }
-
- /* Detach from sibling list */
- c->previous = NULL;
- c->next = NULL;
-
- dom_node_destroy(c);
- }
-
/* Finalise base class */
- dom_node_finalise(doc, &entity->base);
+ _dom_entity_reference_finalise(doc, &entity->base);
/* Destroy fragment */
- dom_document_alloc(doc, entity, 0);
+ _dom_document_alloc(doc, entity, 0);
}
/**
- * Get the textual representation of an EntityReference
+ * Get the textual representation of an EntityRererence
*
* \param entity The entity reference to get the textual representation of
* \param result Pointer to location to receive result
* \return DOM_NO_ERR on success.
*
* The returned string will have its reference count increased. It is
- * the responsibility of the caller to unref the string once it has
+ * the responsibility of the caller to unrer the string once it has
* finished with it.
*/
-dom_exception dom_entity_reference_get_textual_representation(
+dom_exception _dom_entity_reference_get_textual_representation(
struct dom_entity_reference *entity, struct dom_string **result)
{
UNUSED(entity);
@@ -119,3 +109,39 @@ dom_exception dom_entity_reference_get_textual_representation(
return DOM_NOT_SUPPORTED_ERR;
}
+/*-----------------------------------------------------------------------*/
+
+/* Following comes the protected vtable */
+
+/* The virtual destroy function of this class */
+void _dom_er_destroy(struct dom_node_internal *node)
+{
+ _dom_entity_reference_destroy(node->owner,
+ (struct dom_entity_reference *) node);
+}
+
+/* The memory allocator of this class */
+dom_exception _dom_er_alloc(struct dom_document *doc,
+ struct dom_node_internal *n, struct dom_node_internal **ret)
+{
+ UNUSED(n);
+ dom_entity_reference *a;
+
+ a = _dom_document_alloc(doc, NULL, sizeof(struct dom_entity_reference));
+ if (a == NULL)
+ return DOM_NO_MEM_ERR;
+
+ *ret = (dom_node_internal *) a;
+ dom_node_set_owner(*ret, doc);
+
+ return DOM_NO_ERR;
+
+}
+
+/* The copy constructor of this class */
+dom_exception _dom_er_copy(struct dom_node_internal *new,
+ struct dom_node_internal *old)
+{
+ return _dom_node_copy(new, old);
+}
+
diff --git a/src/core/entity_ref.h b/src/core/entity_ref.h
index fa03737..2b83d07 100644
--- a/src/core/entity_ref.h
+++ b/src/core/entity_ref.h
@@ -5,23 +5,42 @@
* Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
*/
-#ifndef dom_internal_core_entityreference_h_
-#define dom_internal_core_entityreference_h_
+#ifndef dom_internal_core_entityrererence_h_
+#define dom_internal_core_entityrererence_h_
#include <dom/core/exceptions.h>
+#include <dom/core/entity_ref.h>
struct dom_document;
struct dom_entity_reference;
struct dom_string;
+struct lwc_string_s;
-dom_exception dom_entity_reference_create(struct dom_document *doc,
- struct dom_string *name, struct dom_string *value,
+dom_exception _dom_entity_reference_create(struct dom_document *doc,
+ struct lwc_string_s *name, struct dom_string *value,
struct dom_entity_reference **result);
-void dom_entity_reference_destroy(struct dom_document *doc,
+void _dom_entity_reference_destroy(struct dom_document *doc,
struct dom_entity_reference *entity);
-dom_exception dom_entity_reference_get_textual_representation(
+#define _dom_entity_reference_initialise _dom_node_initialise
+#define _dom_entity_reference_finalise _dom_node_finalise
+
+/* Following comes the protected vtable */
+void _dom_er_destroy(struct dom_node_internal *node);
+dom_exception _dom_er_alloc(struct dom_document *doc,
+ struct dom_node_internal *n, struct dom_node_internal **ret);
+dom_exception _dom_er_copy(struct dom_node_internal *new,
+ struct dom_node_internal *old);
+
+#define DOM_ER_PROTECT_VTABLE \
+ _dom_er_destroy, \
+ _dom_er_alloc, \
+ _dom_er_copy
+
+/* Helper functions */
+dom_exception _dom_entity_reference_get_textual_representation(
struct dom_entity_reference *entity,
struct dom_string **result);
+
#endif
diff --git a/src/core/implementation.c b/src/core/implementation.c
index e37b27d..e2b6763 100644
--- a/src/core/implementation.c
+++ b/src/core/implementation.c
@@ -59,8 +59,6 @@ dom_exception dom_implementation_has_feature(
* \param public_id The external subset public identifier
* \param system_id The external subset system identifier
* \param doctype Pointer to location to receive result
- * \param alloc Memory (de)allocation function
- * \param pw Pointer to client-specific private data
* \return DOM_NO_ERR on success,
* DOM_INVALID_CHARACTER_ERR if ::qname is invalid,
* DOM_NAMESPACE_ERR if ::qname is malformed,
@@ -79,11 +77,11 @@ dom_exception dom_implementation_has_feature(
dom_exception dom_implementation_create_document_type(
struct dom_implementation *impl, struct dom_string *qname,
struct dom_string *public_id, struct dom_string *system_id,
- struct dom_document_type **doctype,
- dom_alloc alloc, void *pw)
+ dom_alloc alloc, void *pw, struct lwc_context_s *ctx,
+ struct dom_document_type **doctype)
{
return impl->create_document_type(impl, qname, public_id, system_id,
- doctype, alloc, pw);
+ alloc, pw, ctx, doctype);
}
/**
@@ -94,8 +92,6 @@ dom_exception dom_implementation_create_document_type(
* \param qname The qualified name of the document element
* \param doctype The type of document to create
* \param doc Pointer to location to receive result
- * \param alloc Memory (de)allocation function
- * \param pw Pointer to client-specific private data
* \return DOM_NO_ERR on success,
* DOM_INVALID_CHARACTER_ERR if ::qname is invalid,
* DOM_NAMESPACE_ERR if ::qname is malformed, or if ::qname
@@ -125,11 +121,11 @@ dom_exception dom_implementation_create_document(
struct dom_implementation *impl,
struct dom_string *namespace, struct dom_string *qname,
struct dom_document_type *doctype,
- struct dom_document **doc,
- dom_alloc alloc, void *pw)
+ dom_alloc alloc, void *pw, struct lwc_context_s *ctx,
+ struct dom_document **doc)
{
- return impl->create_document(impl, namespace, qname, doctype, doc,
- alloc, pw);
+ return impl->create_document(impl, namespace, qname, doctype, alloc,
+ pw, ctx, doc);
}
/**
@@ -140,8 +136,6 @@ dom_exception dom_implementation_create_document(
* \param feature The requested feature
* \param version The version number of the feature
* \param object Pointer to location to receive object
- * \param alloc Memory (de)allocation function
- * \param pw Pointer to client-specific private data
* \return DOM_NO_ERR.
*
* Any memory allocated by this call should be allocated using
@@ -150,8 +144,7 @@ dom_exception dom_implementation_create_document(
dom_exception dom_implementation_get_feature(
struct dom_implementation *impl,
struct dom_string *feature, struct dom_string *version,
- void **object,
- dom_alloc alloc, void *pw)
+ void **object)
{
- return impl->get_feature(impl, feature, version, object, alloc, pw);
+ return impl->get_feature(impl, feature, version, object);
}
diff --git a/src/core/impllist.c b/src/core/impllist.c
index 522c3f7..2f25926 100644
--- a/src/core/impllist.c
+++ b/src/core/impllist.c
@@ -9,6 +9,9 @@
#include <dom/core/implementation.h>
#include <dom/core/impllist.h>
+extern void dom_implementation_list_destroy(
+ struct dom_implementation_list *list);
+
/**
* Claim a reference on a DOM implementation list
*
@@ -29,22 +32,8 @@ void dom_implementation_list_ref(struct dom_implementation_list *list)
*/
void dom_implementation_list_unref(struct dom_implementation_list *list)
{
- struct dom_implementation_list_item *i, *j;
-
if (--list->refcnt == 0) {
- /* Destroy all list entries */
- for (i = list->head; i; i = j) {
- j = i->next;
-
- /* Unreference the implementation */
- dom_implementation_unref(i->impl);
-
- /* And free the entry */
- list->alloc(i, 0, list->pw);
- }
-
- /* Free the list object */
- list->alloc(list, 0, list->pw);
+ dom_implementation_list_destroy(list);
}
}
diff --git a/src/core/namednodemap.c b/src/core/namednodemap.c
index dab6bbb..ec1e151 100644
--- a/src/core/namednodemap.c
+++ b/src/core/namednodemap.c
@@ -3,8 +3,11 @@
* Licensed under the MIT License,
* http://www.opensource.org/licenses/mit-license.php
* Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
*/
+#include <assert.h>
+
#include <dom/core/element.h>
#include <dom/core/node.h>
#include <dom/core/string.h>
@@ -22,9 +25,10 @@
struct dom_namednodemap {
struct dom_document *owner; /**< Owning document */
- struct dom_node_internal *head; /**< Start of item list */
+ void *priv; /**< Private data */
- dom_node_type type; /**< Type of items in map */
+ struct nnm_operation *opt; /**< The underlaid operation
+ * implementations */
uint32_t refcnt; /**< Reference count */
};
@@ -33,8 +37,8 @@ struct dom_namednodemap {
* Create a namednodemap
*
* \param doc The owning document
- * \param head Start of list containing items in map
- * \param type The type of items in the map
+ * \param priv The private data of this dom_namednodemap
+ * \param opt The operation function pointer
* \param map Pointer to location to receive created map
* \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion
*
@@ -49,23 +53,20 @@ struct dom_namednodemap {
* explicitly reference it. The client must unref the map once it is
* finished with it.
*/
-dom_exception dom_namednodemap_create(struct dom_document *doc,
- struct dom_node_internal *head, dom_node_type type,
+dom_exception _dom_namednodemap_create(struct dom_document *doc,
+ void *priv, struct nnm_operation *opt,
struct dom_namednodemap **map)
{
struct dom_namednodemap *m;
- m = dom_document_alloc(doc, NULL, sizeof(struct dom_namednodemap));
+ m = _dom_document_alloc(doc, NULL, sizeof(struct dom_namednodemap));
if (m == NULL)
return DOM_NO_MEM_ERR;
- dom_node_ref((struct dom_node *) doc);
m->owner = doc;
- dom_node_ref(head);
- m->head = head;
-
- m->type = type;
+ m->priv = priv;
+ m->opt = opt;
m->refcnt = 1;
@@ -81,6 +82,7 @@ dom_exception dom_namednodemap_create(struct dom_document *doc,
*/
void dom_namednodemap_ref(struct dom_namednodemap *map)
{
+ assert(map != NULL);
map->refcnt++;
}
@@ -94,22 +96,15 @@ void dom_namednodemap_ref(struct dom_namednodemap *map)
*/
void dom_namednodemap_unref(struct dom_namednodemap *map)
{
- if (--map->refcnt == 0) {
- struct dom_node_internal *owner =
- (struct dom_node_internal *) map->owner;
+ if (map == NULL)
+ return;
- dom_node_unref(map->head);
-
- /* Remove map from document */
- dom_document_remove_namednodemap(map->owner, map);
+ if (--map->refcnt == 0) {
+ /* Call the implementation specific destroy */
+ map->opt->namednodemap_destroy(map->priv);
/* Destroy the map object */
- dom_document_alloc(map->owner, map, 0);
-
- /* And release our reference on the owning document
- * This must be last as, otherwise, it's possible that
- * the document is destroyed before we are */
- dom_node_unref(owner);
+ _dom_document_alloc(map->owner, map, 0);
}
}
@@ -123,29 +118,8 @@ void dom_namednodemap_unref(struct dom_namednodemap *map)
dom_exception dom_namednodemap_get_length(struct dom_namednodemap *map,
unsigned long *length)
{
- struct dom_node_internal *cur;
- unsigned long len = 0;
-
- switch (map->type) {
- case DOM_ATTRIBUTE_NODE:
- cur = dom_element_get_first_attribute(
- (struct dom_element *) map->head);
- break;
- case DOM_NOTATION_NODE:
- case DOM_ENTITY_NODE:
- /** \todo handle notation and entity nodes */
- default:
- return DOM_NOT_SUPPORTED_ERR;
- break;
- }
-
- for (; cur != NULL; cur = cur->next) {
- len++;
- }
-
- *length = len;
-
- return DOM_NO_ERR;
+ assert(map->opt != NULL);
+ return map->opt->namednodemap_get_length(map->priv, length);
}
/**
@@ -162,33 +136,8 @@ dom_exception dom_namednodemap_get_length(struct dom_namednodemap *map,
dom_exception _dom_namednodemap_get_named_item(struct dom_namednodemap *map,
struct dom_string *name, struct dom_node **node)
{
- struct dom_node_internal *cur;
-
- switch (map->type) {
- case DOM_ATTRIBUTE_NODE:
- cur = dom_element_get_first_attribute(
- (struct dom_element *) map->head);
- break;
- case DOM_NOTATION_NODE:
- case DOM_ENTITY_NODE:
- /** \todo handle notation and entity nodes */
- default:
- return DOM_NOT_SUPPORTED_ERR;
- break;
- }
-
- for (; cur != NULL; cur = cur->next) {
- if (dom_string_cmp(cur->name, name) == 0) {
- break;
- }
- }
-
- if (cur != NULL) {
- dom_node_ref(cur);
- }
- *node = (struct dom_node *) cur;
-
- return DOM_NO_ERR;
+ assert(map->opt != NULL);
+ return map->opt->namednodemap_get_named_item(map->priv, name, node);
}
/**
@@ -218,46 +167,8 @@ dom_exception _dom_namednodemap_get_named_item(struct dom_namednodemap *map,
dom_exception _dom_namednodemap_set_named_item(struct dom_namednodemap *map,
struct dom_node *arg, struct dom_node **node)
{
- dom_exception err;
- struct dom_node_internal *n = (struct dom_node_internal *) arg;
-
- /* Ensure arg and map belong to the same document */
- if (n->owner != map->owner)
- return DOM_WRONG_DOCUMENT_ERR;
-
- /* Ensure map is writable */
- if (_dom_node_readonly(map->head))
- return DOM_NO_MODIFICATION_ALLOWED_ERR;
-
- /* Ensure arg isn't attached to another element */
- if (n->type == DOM_ATTRIBUTE_NODE && n->parent != NULL &&
- n->parent != map->head)
- return DOM_INUSE_ATTRIBUTE_ERR;
-
- /* Ensure arg is permitted in the map */
- if (n->type != map->type)
- return DOM_HIERARCHY_REQUEST_ERR;
-
- /* Now delegate to the container-specific function.
- * NamedNodeMaps are live, so this is fine. */
- switch (map->type) {
- case DOM_ATTRIBUTE_NODE:
- err = dom_element_set_attribute_node(
- (struct dom_element *) map->head,
- (struct dom_attr *) arg,
- (struct dom_attr **) node);
- break;
- case DOM_NOTATION_NODE:
- case DOM_ENTITY_NODE:
- /** \todo handle notation and entity nodes */
- default:
- err = DOM_NOT_SUPPORTED_ERR;
- break;
- }
-
- /* Reference counting is handled by the container-specific call */
-
- return err;
+ assert(map->opt != NULL);
+ return map->opt->namednodemap_set_named_item(map->priv, arg, node);
}
/**
@@ -278,44 +189,8 @@ dom_exception _dom_namednodemap_remove_named_item(
struct dom_namednodemap *map, struct dom_string *name,
struct dom_node **node)
{
- dom_exception err;
-
- /* Ensure map is writable */
- if (_dom_node_readonly(map->head))
- return DOM_NO_MODIFICATION_ALLOWED_ERR;
-
- /* Now delegate to the container-specific function.
- * NamedNodeMaps are live, so this is fine. */
- switch (map->type) {
- case DOM_ATTRIBUTE_NODE:
- {
- struct dom_attr *attr;
-
- err = dom_element_get_attribute_node(
- (struct dom_element *) map->head,
- name, &attr);
- if (err == DOM_NO_ERR) {
- err = dom_element_remove_attribute_node(
- (struct dom_element *) map->head,
- attr, (struct dom_attr **) node);
- if (err == DOM_NO_ERR) {
- /* No longer want attr */
- dom_node_unref((struct dom_node *) attr);
- }
- }
- }
- break;
- case DOM_NOTATION_NODE:
- case DOM_ENTITY_NODE:
- /** \todo handle notation and entity nodes */
- default:
- err = DOM_NOT_SUPPORTED_ERR;
- break;
- }
-
- /* Reference counting is handled by the container-specific call */
-
- return err;
+ assert(map->opt != NULL);
+ return map->opt->namednodemap_remove_named_item(map->priv, name, node);
}
/**
@@ -335,36 +210,8 @@ dom_exception _dom_namednodemap_remove_named_item(
dom_exception _dom_namednodemap_item(struct dom_namednodemap *map,
unsigned long index, struct dom_node **node)
{
- struct dom_node_internal *cur;
- unsigned long count = 0;
-
- switch (map->type) {
- case DOM_ATTRIBUTE_NODE:
- cur = dom_element_get_first_attribute(
- (struct dom_element *) map->head);
- break;
- case DOM_NOTATION_NODE:
- case DOM_ENTITY_NODE:
- /** \todo handle notation and entity nodes */
- default:
- return DOM_NOT_SUPPORTED_ERR;
- break;
- }
-
- for (; cur != NULL; cur = cur->next) {
- count++;
-
- if ((index + 1) == count) {
- break;
- }
- }
-
- if (cur != NULL) {
- dom_node_ref(cur);
- }
- *node = (struct dom_node *) cur;
-
- return DOM_NO_ERR;
+ assert(map->opt != NULL);
+ return map->opt->namednodemap_item(map->priv, index, node);
}
/**
@@ -387,38 +234,9 @@ dom_exception _dom_namednodemap_get_named_item_ns(
struct dom_namednodemap *map, struct dom_string *namespace,
struct dom_string *localname, struct dom_node **node)
{
- struct dom_node_internal *cur;
-
- /** \todo ensure XML feature is supported */
-
- switch (map->type) {
- case DOM_ATTRIBUTE_NODE:
- cur = dom_element_get_first_attribute(
- (struct dom_element *) map->head);
- break;
- case DOM_NOTATION_NODE:
- case DOM_ENTITY_NODE:
- /** \todo handle notation and entity nodes */
- default:
- return DOM_NOT_SUPPORTED_ERR;
- break;
- }
-
- for (; cur != NULL; cur = cur->next) {
- if (((namespace == NULL && cur->namespace == NULL) ||
- (namespace != NULL &&
- dom_string_cmp(cur->namespace, namespace) == 0)) &&
- dom_string_cmp(cur->name, localname) == 0) {
- break;
- }
- }
-
- if (cur != NULL) {
- dom_node_ref(cur);
- }
- *node = (struct dom_node *) cur;
-
- return DOM_NO_ERR;
+ assert(map->opt != NULL);
+ return map->opt->namednodemap_get_named_item_ns(map->priv, namespace,
+ localname, node);
}
/**
@@ -454,48 +272,8 @@ dom_exception _dom_namednodemap_set_named_item_ns(
struct dom_namednodemap *map, struct dom_node *arg,
struct dom_node **node)
{
- dom_exception err;
- struct dom_node_internal *n = (struct dom_node_internal *) arg;
-
- /** \todo ensure XML feature is supported */
-
- /* Ensure arg and map belong to the same document */
- if (n->owner != map->owner)
- return DOM_WRONG_DOCUMENT_ERR;
-
- /* Ensure map is writable */
- if (_dom_node_readonly(map->head))
- return DOM_NO_MODIFICATION_ALLOWED_ERR;
-
- /* Ensure arg isn't attached to another element */
- if (n->type == DOM_ATTRIBUTE_NODE && n->parent != NULL &&
- n->parent != map->head)
- return DOM_INUSE_ATTRIBUTE_ERR;
-
- /* Ensure arg is permitted in the map */
- if (n->type != map->type)
- return DOM_HIERARCHY_REQUEST_ERR;
-
- /* Now delegate to the container-specific function.
- * NamedNodeMaps are live, so this is fine. */
- switch (map->type) {
- case DOM_ATTRIBUTE_NODE:
- err = dom_element_set_attribute_node_ns(
- (struct dom_element *) map->head,
- (struct dom_attr *) arg,
- (struct dom_attr **) node);
- break;
- case DOM_NOTATION_NODE:
- case DOM_ENTITY_NODE:
- /** \todo handle notation and entity nodes */
- default:
- err = DOM_NOT_SUPPORTED_ERR;
- break;
- }
-
- /* Reference counting is handled by the container-specific call */
-
- return err;
+ assert(map->opt != NULL);
+ return map->opt->namednodemap_set_named_item_ns(map->priv, arg, node);
}
/**
@@ -521,61 +299,30 @@ dom_exception _dom_namednodemap_remove_named_item_ns(
struct dom_namednodemap *map, struct dom_string *namespace,
struct dom_string *localname, struct dom_node **node)
{
- dom_exception err;
-
- /** \todo ensure XML feature is supported */
-
- /* Ensure map is writable */
- if (_dom_node_readonly(map->head))
- return DOM_NO_MODIFICATION_ALLOWED_ERR;
-
- /* Now delegate to the container-specific function.
- * NamedNodeMaps are live, so this is fine. */
- switch (map->type) {
- case DOM_ATTRIBUTE_NODE:
- {
- struct dom_attr *attr;
-
- err = dom_element_get_attribute_node_ns(
- (struct dom_element *) map->head,
- namespace, localname, &attr);
- if (err == DOM_NO_ERR) {
- err = dom_element_remove_attribute_node(
- (struct dom_element *) map->head,
- attr, (struct dom_attr **) node);
- if (err == DOM_NO_ERR) {
- /* No longer want attr */
- dom_node_unref((struct dom_node *) attr);
- }
- }
- }
- break;
-case DOM_NOTATION_NODE:
- case DOM_ENTITY_NODE:
- /** \todo handle notation and entity nodes */
- default:
- err = DOM_NOT_SUPPORTED_ERR;
- break;
- }
-
- /* Reference counting is handled by the container-specific call */
-
- return err;
+ assert(map->opt != NULL);
+ return map->opt->namednodemap_remove_named_item_ns(map->priv, namespace,
+ localname, node);
}
/**
- * Match a namednodemap instance against a set of creation parameters
+ * Compare whether two NamedNodeMap are equal.
*
- * \param map The map to match
- * \param head Start of list containing items in map
- * \param type The type of items in the map
- * \return true if list matches, false otherwise
*/
-bool dom_namednodemap_match(struct dom_namednodemap *map,
- struct dom_node_internal *head, dom_node_type type)
+bool _dom_namednodemap_equal(struct dom_namednodemap *m1,
+ struct dom_namednodemap *m2)
{
- if (map->head == head && map->type == type)
- return true;
+ assert(m1->opt != NULL);
+ return (m1->opt == m2->opt && m1->opt->namednodemap_equal(m1->priv,
+ m2->priv));
+}
- return false;
+/**
+ * Update the dom_namednodemap to make it as a proxy of another object
+ *
+ * \param map The dom_namednodemap
+ * \param priv The private data to change to
+ */
+void _dom_namednodemap_update(struct dom_namednodemap *map, void *priv)
+{
+ map->priv = priv;
}
diff --git a/src/core/namednodemap.h b/src/core/namednodemap.h
index 830ab6d..328e433 100644
--- a/src/core/namednodemap.h
+++ b/src/core/namednodemap.h
@@ -18,14 +18,54 @@ struct dom_node;
struct dom_namednodemap;
struct dom_string;
+struct nnm_operation {
+ dom_exception (*namednodemap_get_length)(void *priv,
+ unsigned long *length);
+
+ dom_exception (*namednodemap_get_named_item)(void *priv,
+ struct dom_string *name, struct dom_node **node);
+
+ dom_exception (*namednodemap_set_named_item)(void *priv,
+ struct dom_node *arg, struct dom_node **node);
+
+ dom_exception (*namednodemap_remove_named_item)(
+ void *priv, struct dom_string *name,
+ struct dom_node **node);
+
+ dom_exception (*namednodemap_item)(void *priv,
+ unsigned long index, struct dom_node **node);
+
+ dom_exception (*namednodemap_get_named_item_ns)(
+ void *priv, struct dom_string *namespace,
+ struct dom_string *localname, struct dom_node **node);
+
+ dom_exception (*namednodemap_set_named_item_ns)(
+ void *priv, struct dom_node *arg,
+ struct dom_node **node);
+
+ dom_exception (*namednodemap_remove_named_item_ns)(
+ void *priv, struct dom_string *namespace,
+ struct dom_string *localname, struct dom_node **node);
+
+ void (*namednodemap_destroy)(void *priv);
+
+ bool (*namednodemap_equal)(void *p1, void *p2);
+};
+
/* Create a namednodemap */
-dom_exception dom_namednodemap_create(struct dom_document *doc,
- struct dom_node_internal *head, dom_node_type type,
+dom_exception _dom_namednodemap_create(struct dom_document *doc,
+ void *priv, struct nnm_operation *opt,
struct dom_namednodemap **map);
+/* Update the private data */
+void _dom_namednodemap_update(struct dom_namednodemap *map, void *priv);
+
+/* Test whether two maps are equal */
+bool _dom_namednodemap_equal(struct dom_namednodemap *m1,
+ struct dom_namednodemap *m2);
-/* Match a namednodemap instance against a set of creation parameters */
-bool dom_namednodemap_match(struct dom_namednodemap *map,
- struct dom_node_internal *head, dom_node_type type);
+#define dom_namednodemap_equal(m1, m2) _dom_namednodemap_equal( \
+ (struct dom_namednodemap *) (m1), \
+ (struct dom_namednodemap *) (m2))
#endif
diff --git a/src/core/node.c b/src/core/node.c
index 518d88c..0645769 100644
--- a/src/core/node.c
+++ b/src/core/node.c
@@ -3,6 +3,7 @@
* Licensed under the MIT License,
* http://www.opensource.org/licenses/mit-license.php
* Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
*/
#include <assert.h>
@@ -10,9 +11,15 @@
#include <stdio.h>
#include <dom/core/attr.h>
+#include <dom/core/text.h>
#include <dom/core/document.h>
-#include <dom/core/string.h>
+#include <dom/core/namednodemap.h>
+#include <dom/core/nodelist.h>
+#include <dom/core/implementation.h>
+#include <dom/core/document_type.h>
+#include "core/string.h"
+#include "core/namednodemap.h"
#include "core/attr.h"
#include "core/cdatasection.h"
#include "core/comment.h"
@@ -25,6 +32,7 @@
#include "core/pi.h"
#include "core/text.h"
#include "utils/utils.h"
+#include "utils/resource_mgr.h"
static bool _dom_node_permitted_child(const dom_node_internal *parent,
const dom_node_internal *child);
@@ -48,21 +56,27 @@ static struct dom_node_vtable node_vtable = {
DOM_NODE_VTABLE
};
-/**
- * Create a DOM node and compose the vtable
- *
- * Return The new constructed DOM node or NULL if fail.
- */
-dom_node_internal * dom_node_create(struct dom_document *doc)
+static struct dom_node_protect_vtable node_protect_vtable = {
+ DOM_NODE_PROTECT_VTABLE
+};
+
+
+
+/*----------------------------------------------------------------------*/
+
+/* The constructor and destructor of this object */
+
+/* Create a DOM node and compose the vtable */
+dom_node_internal * _dom_node_create(struct dom_document *doc)
{
- dom_node_internal *node = dom_document_alloc(doc, NULL,
+ dom_node_internal *node = _dom_document_alloc(doc, NULL,
sizeof(struct dom_node_internal));
if (node == NULL)
return NULL;
node->base.vtable = &node_vtable;
- node->destroy = _dom_node_destroy;
+ node->vtable = &node_protect_vtable;
return node;
}
@@ -86,9 +100,6 @@ void _dom_node_destroy(struct dom_node_internal *node)
bool null_owner_permitted = (node->type == DOM_DOCUMENT_NODE ||
node->type == DOM_DOCUMENT_TYPE_NODE);
- /* This function simply acts as a central despatcher
- * for type-specific destructors. */
-
assert(null_owner_permitted || owner != NULL);
if (!null_owner_permitted) {
@@ -98,56 +109,19 @@ void _dom_node_destroy(struct dom_node_internal *node)
dom_node_ref(owner);
}
-/* This type dependent switch is not necessary from now.
- But I still keep them for a while untill all the functions works well.
- switch (node->type) {
- case DOM_ELEMENT_NODE:
- dom_element_destroy(owner, (struct dom_element *) node);
- break;
- case DOM_ATTRIBUTE_NODE:
- dom_attr_destroy(owner, (struct dom_attr *) node);
- break;
- case DOM_TEXT_NODE:
- dom_text_destroy(owner, (struct dom_text *) node);
- break;
- case DOM_CDATA_SECTION_NODE:
- dom_cdata_section_destroy(owner,
- (struct dom_cdata_section *) node);
- break;
- case DOM_ENTITY_REFERENCE_NODE:
- dom_entity_reference_destroy(owner,
- (struct dom_entity_reference *) node);
- break;
- case DOM_ENTITY_NODE:
- break;
- case DOM_PROCESSING_INSTRUCTION_NODE:
- dom_processing_instruction_destroy(owner,
- (struct dom_processing_instruction *) node);
- break;
- case DOM_COMMENT_NODE:
- dom_comment_destroy(owner, (struct dom_comment *) node);
- break;
- case DOM_DOCUMENT_NODE:
- dom_document_destroy((struct dom_document *) node);
- break;
- case DOM_DOCUMENT_TYPE_NODE:
- dom_document_type_destroy((struct dom_document_type *) node);
- break;
- case DOM_DOCUMENT_FRAGMENT_NODE:
- dom_document_fragment_destroy(owner,
- (struct dom_document_fragment *) node);
- break;
- case DOM_NOTATION_NODE:
- break;
- }
-*/
+ /* Finalise this node, this should also destroy all the child nodes. */
+ _dom_node_finalise(owner, node);
+
if (!null_owner_permitted) {
- /* Release the reference we claimed on the document. If this
- * is the last reference held on the document and the list
- * of nodes pending deletion is empty, then the document will
+ /* Release the reference we claimed on the document. If this
+ * is the last reference held on the document and the list
+ * of nodes pending deletion is empty, then the document will
* be destroyed. */
dom_node_unref(owner);
}
+
+ /* Release our memory */
+ _dom_document_alloc(owner, node, 0);
}
/**
@@ -165,13 +139,63 @@ void _dom_node_destroy(struct dom_node_internal *node)
* ::name, ::value, ::namespace, and ::prefix will have their reference
* counts increased.
*/
-dom_exception dom_node_initialise(dom_node_internal *node,
+dom_exception _dom_node_initialise(dom_node_internal *node,
struct dom_document *doc, dom_node_type type,
- struct dom_string *name, struct dom_string *value,
- struct dom_string *namespace, struct dom_string *prefix)
+ struct lwc_string_s *name, struct dom_string *value,
+ struct lwc_string_s *namespace, struct lwc_string_s *prefix)
+{
+ lwc_context *ctx;
+ dom_alloc alloc;
+ void *pw;
+ dom_exception err;
+
+ ctx = _dom_document_get_intern_context(doc);
+ /* The lwc_context for a document never can be NULL */
+ assert(ctx != NULL);
+
+ _dom_document_get_allocator(doc, &alloc, &pw);
+
+ err = _dom_node_initialise_generic(node, doc, alloc, pw, ctx, type,
+ name, value, namespace, prefix);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ return DOM_NO_ERR;
+}
+
+/**
+ * Initialise a DOM node
+ *
+ * \param node The node to initialise
+ * \param doc The document object
+ * \param alloc The memory allocator
+ * \param pw The allocator private pointer data
+ * \param ctx The intern context
+ * \param type The node type required
+ * \param name The node (local) name, or NULL
+ * \param value The node value, or NULL
+ * \param namespace Namespace URI to use for node, or NULL
+ * \param prefix Namespace prefix to use for node, or NULL
+ * \return DOM_NO_ERR on success.
+ *
+ * ::name, ::value, ::namespace, and ::prefix will have their reference
+ * counts increased.
+ */
+dom_exception _dom_node_initialise_generic(
+ struct dom_node_internal *node, struct dom_document *doc,
+ dom_alloc alloc, void *pw, struct lwc_context_s *ctx,
+ dom_node_type type, struct lwc_string_s *name,
+ struct dom_string *value, struct lwc_string_s *namespace,
+ struct lwc_string_s *prefix)
{
+ UNUSED(alloc);
+ UNUSED(pw);
+
+ assert(ctx != NULL);
+ node->owner = doc;
+
if (name != NULL)
- dom_string_ref(name);
+ lwc_context_string_ref(ctx, name);
node->name = name;
if (value != NULL)
@@ -204,15 +228,14 @@ dom_exception dom_node_initialise(dom_node_internal *node,
* deletion. This list will not be forcibly emptied, as it contains
* those nodes (and their sub-trees) in use by client code.
*/
- node->owner = doc;
if (namespace != NULL) {
- dom_string_ref(namespace);
+ lwc_context_string_ref(ctx, namespace);
}
node->namespace = namespace;
if (prefix != NULL) {
- dom_string_ref(prefix);
+ lwc_context_string_ref(ctx, prefix);
}
node->prefix = prefix;
@@ -220,6 +243,12 @@ dom_exception dom_node_initialise(dom_node_internal *node,
node->refcnt = 1;
+ list_init(&node->pending_list);
+ if (node->type != DOM_DOCUMENT_NODE) {
+ /* A Node should be in the pending list when it is created */
+ dom_node_mark_pending(node);
+ }
+
return DOM_NO_ERR;
}
@@ -232,33 +261,62 @@ dom_exception dom_node_initialise(dom_node_internal *node,
* The contents of ::node will be cleaned up. ::node will not be freed.
* All children of ::node should have been removed prior to finalisation.
*/
-void dom_node_finalise(struct dom_document *doc, dom_node_internal *node)
+void _dom_node_finalise(struct dom_document *doc, dom_node_internal *node)
+{
+ lwc_context *ctx;
+ dom_alloc alloc;
+ void *pw;
+
+ ctx = _dom_document_get_intern_context(doc);
+ /* The lwc_context for a document never can be NULL */
+ assert(ctx != NULL);
+
+ _dom_document_get_allocator(doc, &alloc, &pw);
+
+ _dom_node_finalise_generic(node, alloc, pw, ctx);
+}
+
+/**
+ * Finalise a DOM node
+ *
+ * \param node The node to finalise
+ * \param alloc The allocator
+ * \param pw The allocator private data
+ * \param ctx The intern string context
+ */
+void _dom_node_finalise_generic(dom_node_internal *node, dom_alloc alloc,
+ void *pw, struct lwc_context_s *ctx)
{
struct dom_user_data *u, *v;
- /* Standalone DocumentType nodes may not have user data attached */
- assert(node->type != DOM_DOCUMENT_TYPE_NODE ||
- node->user_data == NULL);
+ UNUSED(alloc);
+ UNUSED(pw);
+
+ assert(ctx != NULL);
/* Destroy user data */
for (u = node->user_data; u != NULL; u = v) {
v = u->next;
-
dom_string_unref(u->key);
-
- dom_document_alloc(doc, u, 0);
+ alloc(u, 0, pw);
}
+ node->user_data = NULL;
if (node->prefix != NULL)
- dom_string_unref(node->prefix);
+ lwc_context_string_unref(ctx, node->prefix);
if (node->namespace != NULL)
- dom_string_unref(node->namespace);
-
- /** \todo check if this node is in list of nodes pending deletion.
- * If so, it must be removed from the list, so the document gets
- * destroyed once the list is empty (and no longer referenced) */
- node->owner = NULL;
+ lwc_context_string_unref(ctx, node->namespace);
+
+ /* Destroy all the child nodes of this node */
+ struct dom_node_internal *p = node->first_child;
+ struct dom_node_internal *n = NULL;
+ while (p != NULL) {
+ n = p->next;
+ p->parent = NULL;
+ dom_node_try_destroy(p);
+ p = n;
+ }
/* Paranoia */
node->next = NULL;
@@ -271,7 +329,19 @@ void dom_node_finalise(struct dom_document *doc, dom_node_internal *node)
dom_string_unref(node->value);
if (node->name != NULL)
- dom_string_unref(node->name);
+ lwc_context_string_unref(ctx, node->name);
+
+ /* Detach from the pending list, if we are in it */
+ if (node->pending_list.prev != &node->pending_list) {
+ assert (node->pending_list.next != &node->pending_list);
+ list_del(&node->pending_list);
+ if (node->owner != NULL && node->type != DOM_DOCUMENT_NODE) {
+ /* Deleting this node from the pending list may cause
+ * the list to be null and we should try to destroy
+ * the document. */
+ _dom_document_try_destroy(node->owner);
+ }
+ }
}
/**
@@ -284,6 +354,11 @@ void _dom_node_ref(dom_node_internal *node)
node->refcnt++;
}
+
+/* ---------------------------------------------------------------------*/
+
+/* The public virtual function of this interface Node */
+
/**
* Release a reference on a DOM node
*
@@ -291,15 +366,20 @@ void _dom_node_ref(dom_node_internal *node)
*
* If the reference count reaches zero and the node is not part of any
* document, any memory claimed by the node will be released.
+ *
+ * If the parent of the node is NULL but the reference count does not reach
+ * zero, this means we should put this node to the document's deletion pending
+ * list. When the refcnt reach zero, we delete it.
*/
void _dom_node_unref(dom_node_internal *node)
{
+ if (node == NULL)
+ return;
+
if (node->refcnt > 0)
node->refcnt--;
- if (node->refcnt == 0 && node->parent == NULL) {
- dom_node_destroy(node);
- }
+ dom_node_try_destroy(node);
}
/**
@@ -316,50 +396,85 @@ void _dom_node_unref(dom_node_internal *node)
dom_exception _dom_node_get_node_name(dom_node_internal *node,
struct dom_string **result)
{
- struct dom_string *node_name;
+ struct dom_string *node_name, *temp;
+ dom_document *doc;
+ dom_exception err;
+ struct dom_resource_mgr rm;
+
+ doc = node->owner;
+ /* Document Node and DocumentType Node can have no owner */
+ assert(node->type == DOM_DOCUMENT_TYPE_NODE ||
+ node->type == DOM_DOCUMENT_NODE ||
+ doc != NULL);
assert(node->name != NULL);
+ if (doc != NULL) {
+ _dom_document_get_resource_mgr(doc, &rm);
+ } else if (node->type == DOM_DOCUMENT_TYPE_NODE) {
+ _dom_document_type_get_resource_mgr(
+ (dom_document_type *) node, &rm);
+ }
+
/* If this node was created using a namespace-aware method and
* has a defined prefix, then nodeName is a QName comprised
* of prefix:name. */
- if ((node->type == DOM_ELEMENT_NODE ||
- node->type == DOM_ATTRIBUTE_NODE) &&
- node->prefix != NULL) {
+ if(node->prefix != NULL) {
struct dom_string *colon;
- dom_exception err;
- err = dom_document_create_string(node->owner,
+ err = _dom_resource_mgr_create_string(&rm,
(const uint8_t *) ":", SLEN(":"), &colon);
if (err != DOM_NO_ERR) {
return err;
}
+ /* Make a temp prefix dom_string */
+ err = _dom_resource_mgr_create_string_from_lwcstring(&rm,
+ node->prefix, &temp);
+ if (err != DOM_NO_ERR) {
+ dom_string_unref(colon);
+ return err;
+ }
+
/* Prefix + : */
- err = dom_string_concat(node->prefix, colon, &node_name);
+ err = dom_string_concat(temp, colon, &node_name);
if (err != DOM_NO_ERR) {
+ dom_string_unref(temp);
dom_string_unref(colon);
return err;
}
+ /*Finished with temp*/
+ dom_string_unref(temp);
/* Finished with colon */
dom_string_unref(colon);
+ /* Make a temp name dom_string */
+ err = _dom_resource_mgr_create_string_from_lwcstring(&rm,
+ node->name, &temp);
+ if (err != DOM_NO_ERR) {
+ return err;
+ }
/* Prefix + : + Localname */
- err = dom_string_concat(node_name, node->name, &colon);
+ err = dom_string_concat(node_name, temp, &colon);
if (err != DOM_NO_ERR) {
+ dom_string_unref(temp);
dom_string_unref(node_name);
return err;
}
+ /* Finished with temp */
+ dom_string_unref(temp);
/* Finished with intermediate node name */
dom_string_unref(node_name);
node_name = colon;
} else {
- dom_string_ref(node->name);
-
- node_name = node->name;
+ err = _dom_resource_mgr_create_string_from_lwcstring(&rm,
+ node->name, &node_name);
+ if (err != DOM_NO_ERR) {
+ return err;
+ }
}
*result = node_name;
@@ -384,10 +499,6 @@ dom_exception _dom_node_get_node_name(dom_node_internal *node,
dom_exception _dom_node_get_node_value(dom_node_internal *node,
struct dom_string **result)
{
- if (node->type == DOM_ATTRIBUTE_NODE) {
- return dom_attr_get_value((struct dom_attr *) node, result);
- }
-
if (node->value != NULL)
dom_string_ref(node->value);
@@ -412,6 +523,9 @@ dom_exception _dom_node_get_node_value(dom_node_internal *node,
dom_exception _dom_node_set_node_value(dom_node_internal *node,
struct dom_string *value)
{
+ /* TODO
+ * Whether we should change this to a virtual function?
+ */
/* This is a NOP if the value is defined to be null. */
if (node->type == DOM_DOCUMENT_NODE ||
node->type == DOM_DOCUMENT_FRAGMENT_NODE ||
@@ -507,8 +621,8 @@ dom_exception _dom_node_get_child_nodes(dom_node_internal *node,
if (node->owner == NULL)
return DOM_NOT_SUPPORTED_ERR;
- return dom_document_get_nodelist(node->owner, node,
- NULL, NULL, NULL, result);
+ return _dom_document_get_nodelist(node->owner, DOM_NODELIST_CHILDREN,
+ node, NULL, NULL, NULL, result);
}
/**
@@ -630,13 +744,10 @@ dom_exception _dom_node_get_next_sibling(dom_node_internal *node,
dom_exception _dom_node_get_attributes(dom_node_internal *node,
struct dom_namednodemap **result)
{
- if (node->type != DOM_ELEMENT_NODE) {
- *result = NULL;
-
- return DOM_NO_ERR;
- }
+ UNUSED(node);
+ *result = NULL;
- return dom_element_get_attributes((struct dom_element *) node, result);
+ return DOM_NO_ERR;
}
/**
@@ -654,8 +765,7 @@ dom_exception _dom_node_get_owner_document(dom_node_internal *node,
struct dom_document **result)
{
/* Document nodes have no owner, as far as clients are concerned
- * In reality, they own themselves as this simplifies code elsewhere
- */
+ * In reality, they own themselves as this simplifies code elsewhere */
if (node->type == DOM_DOCUMENT_NODE) {
*result = NULL;
@@ -664,7 +774,7 @@ dom_exception _dom_node_get_owner_document(dom_node_internal *node,
/* If there is an owner, increase its reference count */
if (node->owner != NULL)
- dom_node_ref((dom_node_internal *) node->owner);
+ dom_node_ref(node->owner);
*result = node->owner;
@@ -729,19 +839,10 @@ dom_exception _dom_node_insert_before(dom_node_internal *node,
}
/* Ensure that new_child is permitted as a child of node */
- if (!_dom_node_permitted_child(node, new_child))
+ if (new_child->type != DOM_DOCUMENT_FRAGMENT_NODE &&
+ !_dom_node_permitted_child(node, new_child))
return DOM_HIERARCHY_REQUEST_ERR;
- /* DocumentType nodes are created outside the Document so,
- * if we're trying to attach a DocumentType node, then we
- * also need to set its owner. */
- if (node->type == DOM_DOCUMENT_NODE &&
- new_child->type == DOM_DOCUMENT_TYPE_NODE) {
- /* See long comment in dom_node_initialise as to why
- * we don't ref the document here */
- new_child->owner = (struct dom_document *) node;
- }
-
/* Attempting to insert a node before itself is a NOP */
if (new_child == ref_child) {
dom_node_ref(new_child);
@@ -759,9 +860,19 @@ dom_exception _dom_node_insert_before(dom_node_internal *node,
_dom_node_detach(new_child);
}
- /* If new_child is a DocumentFragment, insert its children
+ /* When a Node is attached, it should be removed from the pending
+ * list */
+ dom_node_remove_pending(new_child);
+
+ /* If new_child is a DocumentFragment, insert its children.
* Otherwise, insert new_child */
if (new_child->type == DOM_DOCUMENT_FRAGMENT_NODE) {
+ /* Test the children of the docment fragment can be appended */
+ dom_node_internal *c = new_child->first_child;
+ for (; c != NULL; c = c->next)
+ if (!_dom_node_permitted_child(node, c))
+ return DOM_HIERARCHY_REQUEST_ERR;
+
if (new_child->first_child != NULL) {
_dom_node_attach_range(new_child->first_child,
new_child->last_child,
@@ -783,6 +894,16 @@ dom_exception _dom_node_insert_before(dom_node_internal *node,
: ref_child);
}
+ /* DocumentType nodes are created outside the Document so,
+ * if we're trying to attach a DocumentType node, then we
+ * also need to set its owner. */
+ if (node->type == DOM_DOCUMENT_NODE &&
+ new_child->type == DOM_DOCUMENT_TYPE_NODE) {
+ /* See long comment in _dom_node_initialise as to why
+ * we don't ref the document here */
+ new_child->owner = (struct dom_document *) node;
+ }
+
/** \todo Is it correct to return DocumentFragments? */
dom_node_ref(new_child);
@@ -853,8 +974,21 @@ dom_exception _dom_node_replace_child(dom_node_internal *node,
}
/* Ensure that new_child is permitted as a child of node */
- if (!_dom_node_permitted_child(node, new_child))
- return DOM_HIERARCHY_REQUEST_ERR;
+ if (new_child->type == DOM_DOCUMENT_FRAGMENT_NODE) {
+ /* If this node is a doc fragment, we should test all its
+ * children nodes */
+ dom_node_internal *c;
+ c = new_child->first_child;
+ while (c != NULL) {
+ if (!_dom_node_permitted_child(node, c))
+ return DOM_HIERARCHY_REQUEST_ERR;
+
+ c = c->next;
+ }
+ } else {
+ if (!_dom_node_permitted_child(node, new_child))
+ return DOM_HIERARCHY_REQUEST_ERR;
+ }
/* Attempting to replace a node with itself is a NOP */
if (new_child == old_child) {
@@ -878,6 +1012,8 @@ dom_exception _dom_node_replace_child(dom_node_internal *node,
/* Sort out the return value */
dom_node_ref(old_child);
+ /* The replaced node should be marded pending */
+ dom_node_mark_pending(old_child);
*result = old_child;
return DOM_NO_ERR;
@@ -922,8 +1058,12 @@ dom_exception _dom_node_remove_child(dom_node_internal *node,
/* Detach the node */
_dom_node_detach(old_child);
- /* Sort out the return value */
+ /* When a Node is removed, it should be destroy. When its refcnt is not
+ * zero, it will be added to the document's deletion pending list.
+ * When a Node is removed, its parent should be NULL, but its owner
+ * should remain to be the document. */
dom_node_ref(old_child);
+ dom_node_try_destroy(old_child);
*result = old_child;
return DOM_NO_ERR;
@@ -1015,15 +1155,67 @@ dom_exception _dom_node_has_child_nodes(dom_node_internal *node, bool *result)
*
* \todo work out what happens when cloning Document, DocumentType, Entity
* and Notation nodes.
+ *
+ * Note: we adopt a OO paradigm, this clone_node just provide a basic operation
+ * of clone. Special clones like Attr/EntitiReference stated above should
+ * provide their overload of this interface in their implementation file.
*/
dom_exception _dom_node_clone_node(dom_node_internal *node, bool deep,
dom_node_internal **result)
{
- UNUSED(node);
- UNUSED(deep);
- UNUSED(result);
+ dom_node_internal *n, *child, *r;
+ dom_exception err;
+ dom_document *doc;
+ dom_user_data *ud;
+
+ doc = node->owner;
+ assert(doc != NULL);
+
+ err = dom_node_alloc(doc, node, &n);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ err = dom_node_copy(n, node);
+ if (err != DOM_NO_ERR) {
+ _dom_document_alloc(doc, n, 0);
+ return err;
+ }
- return DOM_NOT_SUPPORTED_ERR;
+ if (deep) {
+ child = node->first_child;
+ while (child != NULL) {
+ err = dom_node_clone_node(child, deep, (void *) &r);
+ if (err != DOM_NO_ERR) {
+ dom_node_unref(n);
+ return err;
+ }
+
+ err = dom_node_append_child(n, r, (void *) &r);
+ if (err != DOM_NO_ERR) {
+ dom_node_unref(n);
+ return err;
+ }
+
+ /* Clean up the new node, we have reference it two
+ * times */
+ dom_node_unref(r);
+ dom_node_unref(r);
+ child = child->next;
+ }
+ }
+
+ *result = n;
+
+ /* Call the dom_user_data_handlers */
+ ud = node->user_data;
+ while (ud != NULL) {
+ if (ud->handler != NULL)
+ ud->handler(DOM_NODE_CLONED, ud->key, ud->data,
+ (dom_node *) node, (dom_node *) n);
+ ud = ud->next;
+ }
+
+ return DOM_NO_ERR;
}
/**
@@ -1038,9 +1230,36 @@ dom_exception _dom_node_clone_node(dom_node_internal *node, bool deep,
*/
dom_exception _dom_node_normalize(dom_node_internal *node)
{
- UNUSED(node);
+ dom_node_internal *n, *p;
+ dom_exception err;
- return DOM_NOT_SUPPORTED_ERR;
+ p = node->first_child;
+ if (p == NULL)
+ return DOM_NO_ERR;
+
+ n = p->next;
+
+ while (n != NULL) {
+ if (n->type == DOM_TEXT_NODE && p->type == DOM_TEXT_NODE) {
+ err = _dom_merge_adjacent_text(p, n);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ _dom_node_detach(n);
+ dom_node_unref(n);
+ n = p->next;
+ continue;
+ }
+ if (n->type != DOM_TEXT_NODE) {
+ err = dom_node_normalize(n);
+ if (err != DOM_NO_ERR)
+ return err;
+ }
+ p = n;
+ n = n->next;
+ }
+
+ return DOM_NO_ERR;
}
/**
@@ -1054,15 +1273,22 @@ dom_exception _dom_node_normalize(dom_node_internal *node)
* \return DOM_NO_ERR.
*/
dom_exception _dom_node_is_supported(dom_node_internal *node,
- struct dom_string *feature, dom_node_internal *version,
+ struct dom_string *feature, struct dom_string *version,
bool *result)
{
- UNUSED(node);
- UNUSED(feature);
- UNUSED(version);
- UNUSED(result);
+ dom_document *doc;
+ dom_implementation *impl;
+ bool has;
- return DOM_NOT_SUPPORTED_ERR;
+ doc = node->owner;
+ assert(doc != NULL);
+ dom_document_get_implementation(doc, &impl);
+ assert(impl != NULL);
+ dom_implementation_has_feature(impl, feature, version, &has);
+
+ *result = has;
+
+ return DOM_NO_ERR;
}
/**
@@ -1079,13 +1305,18 @@ dom_exception _dom_node_is_supported(dom_node_internal *node,
dom_exception _dom_node_get_namespace(dom_node_internal *node,
struct dom_string **result)
{
+ lwc_context *ctx;
+
+ assert(node->owner != NULL);
+ ctx = _dom_document_get_intern_context(node->owner);
+ assert(ctx != NULL);
+
/* If there is a namespace, increase its reference count */
if (node->namespace != NULL)
- dom_string_ref(node->namespace);
+ lwc_context_string_ref(ctx, node->namespace);
- *result = node->namespace;
-
- return DOM_NO_ERR;
+ return _dom_document_create_string_from_lwcstring(node->owner,
+ node->namespace, result);
}
/**
@@ -1102,13 +1333,19 @@ dom_exception _dom_node_get_namespace(dom_node_internal *node,
dom_exception _dom_node_get_prefix(dom_node_internal *node,
struct dom_string **result)
{
+ lwc_context *ctx;
+
+ assert(node->owner != NULL);
+ ctx = _dom_document_get_intern_context(node->owner);
+ assert(ctx != NULL);
+
/* If there is a prefix, increase its reference count */
if (node->prefix != NULL)
- dom_string_ref(node->prefix);
+ lwc_context_string_ref(ctx, node->prefix);
- *result = node->prefix;
-
- return DOM_NO_ERR;
+ return _dom_document_create_string_from_lwcstring(node->owner,
+ node->prefix,
+ result);
}
/**
@@ -1137,6 +1374,13 @@ dom_exception _dom_node_get_prefix(dom_node_internal *node,
dom_exception _dom_node_set_prefix(dom_node_internal *node,
struct dom_string *prefix)
{
+ dom_exception err;
+ lwc_string *str;
+ lwc_context *docctx;
+
+ docctx = _dom_document_get_intern_context(node->owner);
+ assert(docctx != NULL);
+
/* Only Element and Attribute nodes created using
* namespace-aware methods may have a prefix */
if ((node->type != DOM_ELEMENT_NODE &&
@@ -1154,7 +1398,7 @@ dom_exception _dom_node_set_prefix(dom_node_internal *node,
/* No longer want existing prefix */
if (node->prefix != NULL) {
- dom_string_unref(node->prefix);
+ lwc_context_string_unref(docctx, node->prefix);
}
/* Set the prefix */
@@ -1163,8 +1407,11 @@ dom_exception _dom_node_set_prefix(dom_node_internal *node,
if (dom_string_length(prefix) == 0) {
node->prefix = NULL;
} else {
- dom_string_ref(prefix);
- node->prefix = prefix;
+ err = _dom_node_get_intern_string(node, prefix, &str);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ node->prefix = str;
}
} else {
node->prefix = NULL;
@@ -1186,7 +1433,13 @@ dom_exception _dom_node_set_prefix(dom_node_internal *node,
*/
dom_exception _dom_node_get_local_name(dom_node_internal *node,
struct dom_string **result)
-{
+{
+ lwc_context *ctx;
+
+ assert(node->owner != NULL);
+ ctx = _dom_document_get_intern_context(node->owner);
+ assert(ctx != NULL);
+
/* Only Element and Attribute nodes may have a local name */
if (node->type != DOM_ELEMENT_NODE &&
node->type != DOM_ATTRIBUTE_NODE) {
@@ -1194,19 +1447,13 @@ dom_exception _dom_node_get_local_name(dom_node_internal *node,
return DOM_NO_ERR;
}
- /* Node must have been created using a namespace-aware method */
- if (node->namespace == NULL) {
- *result = NULL;
- return DOM_NO_ERR;
- }
-
/* The node may have a local name, reference it if so */
if (node->name != NULL) {
- dom_string_ref(node->name);
+ lwc_context_string_ref(ctx, node->name);
}
- *result = node->name;
- return DOM_NO_ERR;
+ return _dom_document_create_string_from_lwcstring(node->owner,
+ node->name, result);
}
/**
@@ -1218,13 +1465,10 @@ dom_exception _dom_node_get_local_name(dom_node_internal *node,
*/
dom_exception _dom_node_has_attributes(dom_node_internal *node, bool *result)
{
- if (node->type != DOM_ELEMENT_NODE) {
- *result = false;
-
- return DOM_NO_ERR;
- }
+ UNUSED(node);
+ *result = false;
- return dom_element_has_attributes((struct dom_element *) node, result);
+ return DOM_NO_ERR;
}
/**
@@ -1237,6 +1481,9 @@ dom_exception _dom_node_has_attributes(dom_node_internal *node, bool *result)
* The returned string will have its reference count increased. It is
* the responsibility of the caller to unref the string once it has
* finished with it.
+ *
+ * We don't support this API now, so this function call should always
+ * return DOM_NOT_SUPPORTED_ERR.
*/
dom_exception _dom_node_get_base(dom_node_internal *node,
struct dom_string **result)
@@ -1258,6 +1505,9 @@ dom_exception _dom_node_get_base(dom_node_internal *node,
* implementations.
*
* The result is a bitfield of dom_document_position values.
+ *
+ * We don't support this API now, so this function call should always
+ * return DOM_NOT_SUPPORTED_ERR.
*/
dom_exception _dom_node_compare_document_position(dom_node_internal *node,
dom_node_internal *other, uint16_t *result)
@@ -1286,10 +1536,21 @@ dom_exception _dom_node_compare_document_position(dom_node_internal *node,
dom_exception _dom_node_get_text_content(dom_node_internal *node,
struct dom_string **result)
{
- UNUSED(node);
- UNUSED(result);
+ dom_node_internal *n;
+ dom_string *str;
+ dom_string *ret;
- return DOM_NOT_SUPPORTED_ERR;
+ assert(node->owner != NULL);
+
+ for (n = node->first_child; n != NULL; n = n->next) {
+ dom_node_get_text_content(n, &ret);
+ dom_string_concat(str, ret, &str);
+ }
+
+ dom_string_ref(str);
+ *result = str;
+
+ return DOM_NO_ERR;
}
/**
@@ -1306,10 +1567,36 @@ dom_exception _dom_node_get_text_content(dom_node_internal *node,
dom_exception _dom_node_set_text_content(dom_node_internal *node,
struct dom_string *content)
{
- UNUSED(node);
- UNUSED(content);
+ dom_node_internal *n, *p, *r;
+ dom_document *doc;
+ dom_text *text;
+ dom_exception err;
+
+ n = node->first_child;
+
+ while (n != NULL) {
+ p = n;
+ n = n->next;
+ /* Add the (void *) casting to avoid gcc warning:
+ * dereferencing type-punned pointer will break
+ * strict-aliasing rules */
+ err = dom_node_remove_child(node, n, (void *) &r);
+ if (err != DOM_NO_ERR)
+ return err;
+ }
- return DOM_NOT_SUPPORTED_ERR;
+ doc = node->owner;
+ assert(doc != NULL);
+
+ err = dom_document_create_text_node(doc, content, &text);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ err = dom_node_append_child(node, text, (void *) &r);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ return DOM_NO_ERR;
}
/**
@@ -1322,8 +1609,8 @@ dom_exception _dom_node_set_text_content(dom_node_internal *node,
*
* This tests if the two nodes reference the same object.
*/
-dom_exception _dom_node_is_same(dom_node_internal *node, dom_node_internal *other,
- bool *result)
+dom_exception _dom_node_is_same(dom_node_internal *node,
+ dom_node_internal *other, bool *result)
{
*result = (node == other);
@@ -1345,11 +1632,12 @@ dom_exception _dom_node_is_same(dom_node_internal *node, dom_node_internal *othe
dom_exception _dom_node_lookup_prefix(dom_node_internal *node,
struct dom_string *namespace, struct dom_string **result)
{
- UNUSED(node);
- UNUSED(namespace);
- UNUSED(result);
+ if (node->parent != NULL)
+ return dom_node_lookup_prefix(node, namespace, result);
+ else
+ *result = NULL;
- return DOM_NOT_SUPPORTED_ERR;
+ return DOM_NO_ERR;
}
/**
@@ -1363,11 +1651,11 @@ dom_exception _dom_node_lookup_prefix(dom_node_internal *node,
dom_exception _dom_node_is_default_namespace(dom_node_internal *node,
struct dom_string *namespace, bool *result)
{
- UNUSED(node);
- UNUSED(namespace);
- UNUSED(result);
-
- return DOM_NOT_SUPPORTED_ERR;
+ if (node->parent != NULL)
+ return dom_node_is_default_namespace(node, namespace, result);
+ else
+ *result = false;
+ return DOM_NO_ERR;
}
/**
@@ -1385,11 +1673,12 @@ dom_exception _dom_node_is_default_namespace(dom_node_internal *node,
dom_exception _dom_node_lookup_namespace(dom_node_internal *node,
struct dom_string *prefix, struct dom_string **result)
{
- UNUSED(node);
- UNUSED(prefix);
- UNUSED(result);
+ if (node->parent != NULL)
+ return dom_node_lookup_namespace(node->parent, prefix, result);
+ else
+ *result = NULL;
- return DOM_NOT_SUPPORTED_ERR;
+ return DOM_NO_ERR;
}
/**
@@ -1410,15 +1699,106 @@ dom_exception _dom_node_lookup_namespace(dom_node_internal *node,
* + publicId, systemId, internalSubset are equal
* + The node entities are equal
* + The node notations are equal
+ * TODO: in document_type, we should override this virtual function
*/
dom_exception _dom_node_is_equal(dom_node_internal *node,
dom_node_internal *other, bool *result)
{
- UNUSED(node);
- UNUSED(other);
- UNUSED(result);
+ dom_exception err;
+ dom_string *s1, *s2;
+ lwc_context *c1, *c2;
+ dom_namednodemap *m1, *m2;
+ dom_nodelist *l1, *l2;
- return DOM_NOT_SUPPORTED_ERR;
+ if (node->type != other->type){
+ *result = false;
+ return DOM_NO_ERR;
+ }
+
+ assert(node->owner != NULL);
+ assert(other->owner != NULL);
+
+ err = dom_node_get_node_name(node, &s1);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ err = dom_node_get_node_name(other, &s2);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ if (dom_string_cmp(s1, s2) != 0) {
+ *result = false;
+ return DOM_NO_ERR;
+ }
+
+ c1 = _dom_document_get_intern_context(node->owner);
+ assert(c1 != NULL);
+
+ c2 = _dom_document_get_intern_context(other->owner);
+ assert(c2 != NULL);
+
+ if (c1 == c2) {
+ if (node->name != other->name ||
+ node->namespace != other->namespace ||
+ node->prefix != other->prefix) {
+ *result = false;
+ return DOM_NO_ERR;
+ }
+ } else {
+ if (_dom_lwc_string_compare_raw(node->name, other->name) != 0){
+ *result = false;
+ return DOM_NO_ERR;
+ }
+
+ if (_dom_lwc_string_compare_raw(node->namespace,
+ other->namespace) != 0){
+ *result = false;
+ return DOM_NO_ERR;
+ }
+
+ if (_dom_lwc_string_compare_raw(node->prefix,
+ other->prefix) != 0){
+ *result = false;
+ return DOM_NO_ERR;
+ }
+ }
+
+ if (dom_string_cmp(node->value, other->value) != 0) {
+ *result = false;
+ return DOM_NO_ERR;
+ }
+
+ // Following comes the attributes
+ err = dom_node_get_attributes(node, &m1);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ err = dom_node_get_attributes(other, &m2);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ if (dom_namednodemap_equal(m1, m2) != true) {
+ *result = false;
+ return DOM_NO_ERR;
+ }
+
+ // Finally the childNodes
+ err = dom_node_get_child_nodes(node, &l1);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ err = dom_node_get_child_nodes(other, &l2);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ if (dom_nodelist_equal(l1, l2) != true) {
+ *result = false;
+ return DOM_NO_ERR;
+ }
+
+ *result = true;
+
+ return DOM_NO_ERR;
}
/**
@@ -1435,12 +1815,23 @@ dom_exception _dom_node_get_feature(dom_node_internal *node,
struct dom_string *feature, struct dom_string *version,
void **result)
{
- UNUSED(node);
- UNUSED(feature);
- UNUSED(version);
- UNUSED(result);
+ dom_document *doc;
+ dom_implementation *impl;
+ bool has;
+
+ doc = node->owner;
+ assert(doc != NULL);
+ dom_document_get_implementation(doc, &impl);
+ assert(impl != NULL);
+ dom_implementation_has_feature(impl, feature, version, &has);
+
+ if (has) {
+ *result = node;
+ } else {
+ *result = NULL;
+ }
- return DOM_NOT_SUPPORTED_ERR;
+ return DOM_NO_ERR;
}
/**
@@ -1479,14 +1870,14 @@ dom_exception _dom_node_set_user_data(dom_node_internal *node,
*result = ud->data;
- dom_document_alloc(node->owner, ud, 0);
+ _dom_document_alloc(node->owner, ud, 0);
return DOM_NO_ERR;
}
/* Otherwise, create a new user data object if one wasn't found */
if (ud == NULL) {
- ud = dom_document_alloc(node->owner, NULL,
+ ud = _dom_document_alloc(node->owner, NULL,
sizeof(struct dom_user_data));
if (ud == NULL)
return DOM_NO_MEM_ERR;
@@ -1542,9 +1933,124 @@ dom_exception _dom_node_get_user_data(dom_node_internal *node,
return DOM_NO_ERR;
}
-/* */
-/*----------------------------------------------------------------------------*/
-/* */
+
+/*--------------------------------------------------------------------------*/
+
+/* The protected virtual functions */
+
+/* We should never call this pure-virtual function directly */
+dom_exception _dom_node_alloc(struct dom_document *doc,
+ struct dom_node_internal *n, struct dom_node_internal **ret)
+{
+ UNUSED(doc);
+ UNUSED(n);
+ UNUSED(ret);
+
+ return DOM_NOT_SUPPORTED_ERR;
+}
+
+
+/* Copy the internal attributes of a Node from old to new */
+dom_exception _dom_node_copy(dom_node_internal *new, dom_node_internal *old)
+{
+ lwc_context *nctx, *octx;
+ dom_exception err;
+
+ new->vtable = old->vtable;
+ new->base.vtable = old->base.vtable;
+
+ assert(old->owner != NULL);
+ octx = _dom_document_get_intern_context(old->owner);
+ assert(octx != NULL);
+
+ assert(new->owner != NULL);
+ nctx = _dom_document_get_intern_context(old->owner);
+ assert(nctx != NULL);
+
+ new->type = old->type;
+ new->parent = NULL;
+ new->first_child = NULL;
+ new->last_child = NULL;
+ new->previous = NULL;
+ new->next = NULL;
+ new->owner = old->owner;
+
+ if (octx == nctx) {
+ lwc_context_string_ref(octx, old->name);
+ new->name = old->name;
+
+ if (old->namespace != NULL)
+ lwc_context_string_ref(octx, old->namespace);
+ new->namespace = old->namespace;
+
+ if (old->prefix != NULL)
+ lwc_context_string_ref(octx, old->prefix);
+ new->prefix = old->prefix;
+ } else {
+ lwc_string *str;
+ lwc_error lerr;
+
+ lerr = lwc_context_intern(nctx, lwc_string_data(old->name),
+ lwc_string_length(old->name), &str);
+ if (lerr != lwc_error_ok)
+ return _dom_exception_from_lwc_error(lerr);
+
+ new->name = str;
+
+ if (old->namespace != NULL) {
+ lerr = lwc_context_intern(nctx,
+ lwc_string_data(old->namespace),
+ lwc_string_length(old->namespace),
+ &str);
+ if (lerr != lwc_error_ok)
+ return _dom_exception_from_lwc_error(lerr);
+
+ new->namespace = str;
+ } else
+ new->namespace = NULL;
+
+ if (old->prefix != NULL) {
+ lerr = lwc_context_intern(nctx,
+ lwc_string_data(old->prefix),
+ lwc_string_length(old->prefix), &str);
+ if (lerr != lwc_error_ok)
+ return _dom_exception_from_lwc_error(lerr);
+
+ new->prefix = str;
+ } else
+ new->prefix = NULL;
+ }
+
+ dom_alloc al;
+ void *pw;
+
+ if (old->value != NULL) {
+ _dom_document_get_allocator(new->owner, &al, &pw);
+ dom_string *value;
+ err = dom_string_clone(al, pw, old->value, &value);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ new->value = value;
+ } else {
+ new->value = NULL;
+ }
+
+ new->user_data = NULL;
+ new->refcnt = 1;
+
+ list_init(&new->pending_list);
+ /* The new copyed node has no parent,
+ * so it should be put in the pending list. */
+ dom_node_mark_pending(new);
+
+ return DOM_NO_ERR;
+}
+
+
+/*--------------------------------------------------------------------------*/
+
+/* The helper functions */
/**
* Determine if a node is permitted as a child of another node
@@ -1626,20 +2132,18 @@ bool _dom_node_permitted_child(const dom_node_internal *parent,
*/
bool _dom_node_readonly(const dom_node_internal *node)
{
- /* DocumentType and Notation nodes are read only */
- if (node->type == DOM_DOCUMENT_TYPE_NODE ||
- node->type == DOM_NOTATION_NODE)
- return true;
+ const dom_node_internal *n = node;
- /* Entity nodes and their descendants are read only */
- for (; node != NULL; node = node->parent) {
- if (node->type == DOM_ENTITY_NODE)
- return true;
- }
+ /* DocumentType and Notation ns are read only */
+ if (n->type == DOM_DOCUMENT_TYPE_NODE ||
+ n->type == DOM_NOTATION_NODE)
+ return true;
- /* EntityReference nodes and their descendants are read only */
- for (; node != NULL; node = node->parent) {
- if (node->type == DOM_ENTITY_REFERENCE_NODE)
+ /* Entity ns and their descendants are read only
+ * EntityReference ns and their descendants are read only */
+ for (n = node; n != NULL; n = n->parent) {
+ if (n->type == DOM_ENTITY_NODE
+ || n->type == DOM_ENTITY_REFERENCE_NODE)
return true;
}
@@ -1668,6 +2172,10 @@ void _dom_node_attach(dom_node_internal *node, dom_node_internal *parent,
*/
void _dom_node_detach(dom_node_internal *node)
{
+ /* When a Node is not in the document tree, it must be in the
+ pending list */
+ dom_node_mark_pending(node);
+
_dom_node_detach_range(node, node);
}
@@ -1701,8 +2209,9 @@ void _dom_node_attach_range(dom_node_internal *first,
else
parent->last_child = last;
- for (dom_node_internal *n = first; n != last->next; n = n->next)
+ for (dom_node_internal *n = first; n != last->next; n = n->next) {
n->parent = parent;
+ }
}
/**
@@ -1726,8 +2235,9 @@ void _dom_node_detach_range(dom_node_internal *first,
else
last->parent->last_child = first->previous;
- for (dom_node_internal *n = first; n != last->next; n = n->next)
+ for (dom_node_internal *n = first; n != last->next; n = n->next) {
n->parent = NULL;
+ }
first->previous = NULL;
last->next = NULL;
@@ -1771,9 +2281,220 @@ void _dom_node_replace(dom_node_internal *old,
else
old->parent->last_child = last;
- for (dom_node_internal *n = first; n != last->next; n = n->next)
+ for (dom_node_internal *n = first; n != last->next; n = n->next) {
n->parent = old->parent;
+ }
old->previous = old->next = old->parent = NULL;
}
+/**
+ * Migrate one lwc_string from one context to another, this function
+ * may be used when we import/adopt a Node between documents.
+ *
+ * \param old The source context
+ * \param new The new context
+ * \param string The lwc_string to migrate
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ */
+dom_exception _redocument_lwcstring(lwc_context *old, lwc_context *new,
+ lwc_string **string)
+{
+ lwc_string *str;
+ lwc_error lerr;
+
+ lerr = lwc_context_intern(new, lwc_string_data(*string),
+ lwc_string_length(*string), &str);
+ if (lerr != lwc_error_ok)
+ return _dom_exception_from_lwc_error(lerr);
+
+ lwc_context_string_unref(old, *string);
+ *string = str;
+
+ return DOM_NO_ERR;
+}
+
+/**
+ * Migrate one dom_string from one document to another, this function
+ * may be used when we import/adopt a Node between documents.
+ *
+ * \param old The source document
+ * \param new The new document
+ * \param string The dom_string to migrate
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ */
+dom_exception _redocument_domstring(dom_document *old, dom_document* new,
+ dom_string **string)
+{
+ dom_exception err;
+ dom_string *str;
+
+ UNUSED(old);
+ err = _dom_document_create_string(new, NULL, 0, &str);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ err = dom_string_dup(*string, &str);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ dom_string_unref(*string);
+ *string = str;
+
+ return DOM_NO_ERR;
+}
+
+/**
+ * Merge two adjacent text nodes into one text node.
+ *
+ * \param p The first text node
+ * \param n The second text node
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ */
+dom_exception _dom_merge_adjacent_text(dom_node_internal *p,
+ dom_node_internal *n)
+{
+ assert(p->type = DOM_TEXT_NODE);
+ assert(n->type = DOM_TEXT_NODE);
+
+ dom_string *str;
+ dom_exception err;
+
+ err = dom_text_get_whole_text(n, &str);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ err = dom_characterdata_append_data(p, str);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ dom_string_unref(str);
+
+ return DOM_NO_ERR;
+}
+
+/**
+ * Intern a dom_string using the node's owner document's lwc_context
+ *
+ * \param node The node
+ * \param str The dom_string to be interned
+ * \param intern The returned interned string
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ */
+dom_exception _dom_node_get_intern_string(dom_node_internal *node,
+ dom_string *str, lwc_string **intern)
+{
+ dom_exception err;
+ lwc_context *ctx, *docctx;
+ lwc_string *ret;
+
+ assert(str != NULL);
+ assert(node->owner != NULL);
+
+ docctx = _dom_document_get_intern_context(node->owner);
+ assert(docctx != NULL);
+
+ err = dom_string_get_intern(str, &ctx, &ret);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ if (ctx != docctx) {
+ err = _dom_string_intern(str, docctx, &ret);
+ if (err != DOM_NO_ERR)
+ return err;
+ }
+
+ *intern = ret;
+
+ return DOM_NO_ERR;
+}
+
+/**
+ * Unref a lwc_string used in this node
+ *
+ * \param node The node
+ * \param intern The lwc_string to unref
+ */
+void _dom_node_unref_intern_string(dom_node_internal *node,
+ struct lwc_string_s *intern)
+{
+ struct dom_resource_mgr rm;
+ struct dom_document *doc = node->owner;
+
+ if (doc != NULL) {
+ _dom_document_get_resource_mgr(doc, &rm);
+ } else if (node->type == DOM_DOCUMENT_TYPE_NODE) {
+ _dom_document_type_get_resource_mgr(
+ (dom_document_type *) node, &rm);
+ }
+
+ lwc_context_string_unref(rm.ctx, intern);
+}
+
+/**
+ * Try to destroy this node.
+ *
+ * \param node The node to destroy
+ *
+ * When some node owns this node, (such as an elment owns its attribute nodes)
+ * when this node being not owned, the owner should call this function to try
+ * to destroy this node.
+ *
+ * @note: Owning a node does not means this node's refcnt is above zero.
+ */
+void _dom_node_try_destroy(dom_node_internal *node)
+{
+ if (node == NULL)
+ return;
+
+ if (node->parent == NULL) {
+ if (node->refcnt == 0) {
+ dom_node_destroy(node);
+ } else if (node->pending_list.prev == &node->pending_list){
+ assert (node->pending_list.next == &node->pending_list);
+ list_append(&node->owner->pending_nodes,
+ &node->pending_list);
+ }
+ }
+}
+
+/**
+ * To add some node to the pending list, when a node is removed from its parent
+ * or an attribute is removed from its element
+ *
+ * \param node The Node instance
+ */
+void _dom_node_mark_pending(dom_node_internal *node)
+{
+ struct dom_document *doc = node->owner;
+
+ /* TODO: the pending_list is located at in dom_document, but some
+ * nodes can be created without a document created, such as a
+ * dom_document_type node. For this reason, we should test whether
+ * the doc is NULL. */
+ if (doc != NULL) {
+ /* The node must not be in the pending list */
+ assert(node->pending_list.prev == &node->pending_list);
+
+ list_append(&doc->pending_nodes, &node->pending_list);
+ }
+}
+
+/**
+ * To remove the node from the pending list, this may happen when
+ * a node is removed and then appended to another parent
+ *
+ * \param node The Node instance
+ */
+void _dom_node_remove_pending(dom_node_internal *node)
+{
+ struct dom_document *doc = node->owner;
+
+ if (doc != NULL) {
+ /* The node must be in the pending list */
+ assert(node->pending_list.prev != &node->pending_list);
+
+ list_del(&node->pending_list);
+ }
+}
+
diff --git a/src/core/node.h b/src/core/node.h
index 27c9f35..68776da 100644
--- a/src/core/node.h
+++ b/src/core/node.h
@@ -10,7 +10,12 @@
#include <stdbool.h>
+#include <libwapcaplet/libwapcaplet.h>
+
#include <dom/core/node.h>
+#include <dom/functypes.h>
+
+#include "utils/list.h"
/**
* User data context attached to a DOM node
@@ -23,6 +28,23 @@ struct dom_user_data {
struct dom_user_data *next; /**< Next in list */
struct dom_user_data *prev; /**< Previous in list */
};
+typedef struct dom_user_data dom_user_data;
+
+/**
+ * The internally used virtual function table.
+ */
+typedef struct dom_node_protect_vtable {
+
+ void (*destroy)(dom_node_internal *n);
+ /**< The destroy virtual function, it
+ * should be private to client */
+ dom_exception (*alloc)(struct dom_document *doc,
+ dom_node_internal *n, dom_node_internal **ret);
+ /**< Allocate the memory of the new Node */
+ dom_exception (*copy)(dom_node_internal *new, dom_node_internal *old);
+ /**< Copy the old to new as well as
+ * all its attributes, but not its children */
+} dom_node_protect_vtable;
/**
* The real DOM node object
@@ -31,13 +53,11 @@ struct dom_user_data {
*/
struct dom_node_internal {
struct dom_node base; /**< The vtable base */
- void (*destroy)(dom_node_internal *n);
- /**< The destroy vitual function, it
- * should be privated to client */
+ void *vtable; /**< The protected vtable */
- struct dom_string *name; /**< Node name (this is the local part
- * of a QName in the cases where a
- * namespace exists) */
+ struct lwc_string_s *name; /**< Node name (this is the local part
+ * of a QName in the cases where a
+ * namespace exists) */
struct dom_string *value; /**< Node value */
dom_node_type type; /**< Node type */
dom_node_internal *parent; /**< Parent node */
@@ -48,27 +68,37 @@ struct dom_node_internal {
struct dom_document *owner; /**< Owning document */
- struct dom_string *namespace; /**< Namespace URI */
- struct dom_string *prefix; /**< Namespace prefix */
+ struct lwc_string_s *namespace; /**< Namespace URI */
+ struct lwc_string_s *prefix; /**< Namespace prefix */
struct dom_user_data *user_data; /**< User data list */
uint32_t refcnt; /**< Reference count */
+
+ struct list_entry pending_list; /**< The document delete pending list */
};
-dom_node_internal * dom_node_create(struct dom_document *doc);
+dom_node_internal * _dom_node_create(struct dom_document *doc);
-dom_exception dom_node_initialise(struct dom_node_internal *node,
+dom_exception _dom_node_initialise(struct dom_node_internal *node,
struct dom_document *doc, dom_node_type type,
- struct dom_string *name, struct dom_string *value,
- struct dom_string *namespace, struct dom_string *prefix);
+ struct lwc_string_s *name, struct dom_string *value,
+ struct lwc_string_s *namespace, struct lwc_string_s *prefix);
-void dom_node_finalise(struct dom_document *doc, dom_node_internal *node);
+dom_exception _dom_node_initialise_generic(
+ struct dom_node_internal *node, struct dom_document *doc,
+ dom_alloc alloc, void *pw, struct lwc_context_s *ctx,
+ dom_node_type type, struct lwc_string_s *name,
+ struct dom_string *value, struct lwc_string_s *namespace,
+ struct lwc_string_s *prefix);
+
+void _dom_node_finalise(struct dom_document *doc, dom_node_internal *node);
+void _dom_node_finalise_generic(dom_node_internal *node, dom_alloc alloc,
+ void *pw, struct lwc_context_s *ctx);
bool _dom_node_readonly(const dom_node_internal *node);
/* The DOM Node's vtable methods */
-void _dom_node_destroy(struct dom_node_internal *node);
dom_exception _dom_node_get_node_name(dom_node_internal *node,
struct dom_string **result);
dom_exception _dom_node_get_node_value(dom_node_internal *node,
@@ -110,7 +140,7 @@ dom_exception _dom_node_clone_node(dom_node_internal *node, bool deep,
dom_node_internal **result);
dom_exception _dom_node_normalize(dom_node_internal *node);
dom_exception _dom_node_is_supported(dom_node_internal *node,
- struct dom_string *feature, dom_node_internal *version,
+ struct dom_string *feature, struct dom_string *version,
bool *result);
dom_exception _dom_node_get_namespace(dom_node_internal *node,
struct dom_string **result);
@@ -129,8 +159,8 @@ dom_exception _dom_node_get_text_content(dom_node_internal *node,
struct dom_string **result);
dom_exception _dom_node_set_text_content(dom_node_internal *node,
struct dom_string *content);
-dom_exception _dom_node_is_same(dom_node_internal *node, dom_node_internal *other,
- bool *result);
+dom_exception _dom_node_is_same(dom_node_internal *node,
+ dom_node_internal *other, bool *result);
dom_exception _dom_node_lookup_prefix(dom_node_internal *node,
struct dom_string *namespace, struct dom_string **result);
dom_exception _dom_node_is_default_namespace(dom_node_internal *node,
@@ -188,11 +218,85 @@ dom_exception _dom_node_get_user_data(dom_node_internal *node,
_dom_node_get_user_data
+/* Following comes the protected vtable */
+void _dom_node_destroy(struct dom_node_internal *node);
+dom_exception _dom_node_alloc(struct dom_document *doc,
+ struct dom_node_internal *n, struct dom_node_internal **ret);
+dom_exception _dom_node_copy(struct dom_node_internal *new,
+ struct dom_node_internal *old);
+
+#define DOM_NODE_PROTECT_VTABLE \
+ _dom_node_destroy, \
+ _dom_node_alloc, \
+ _dom_node_copy
+
+
/* The destroy API should be used inside DOM module */
-static inline void dom_node_destroy(struct dom_node *node)
+static inline void dom_node_destroy(struct dom_node_internal *node)
+{
+ ((dom_node_protect_vtable *) node->vtable)->destroy(node);
+}
+#define dom_node_destroy(n) dom_node_destroy((dom_node_internal *) (n))
+
+/* Allocate the Node */
+static inline dom_exception dom_node_alloc(struct dom_document *doc,
+ struct dom_node_internal *n, struct dom_node_internal **ret)
+{
+ return ((dom_node_protect_vtable *) n->vtable)->alloc(doc, n, ret);
+}
+#define dom_node_alloc(d,n,r) dom_node_alloc((struct dom_document *) (d), \
+ (dom_node_internal *) (n), (dom_node_internal **) (r))
+
+
+/* Copy the Node old to new */
+static inline dom_exception dom_node_copy(struct dom_node_internal *new,
+ struct dom_node_internal *old)
{
- ((dom_node_internal *) node)->destroy((dom_node_internal *) node);
+ return ((dom_node_protect_vtable *) old->vtable)->copy(new, old);
}
-#define dom_node_destroy(n) dom_node_destroy((dom_node *) (n))
+#define dom_node_copy(n,o) dom_node_copy((dom_node_internal *) (n), \
+ (dom_node_internal *) (o))
+
+/* Following are some helper functions */
+#define dom_node_get_owner(n) ((dom_node_internal *) (n))->owner
+
+#define dom_node_set_owner(n, d) ((dom_node_internal *) (n))->owner = \
+ (struct dom_document *) (d)
+
+#define dom_node_get_parent(n) ((dom_node_internal *) (n))->parent
+
+#define dom_node_set_parent(n, p) ((dom_node_internal *) (n))->parent = \
+ (dom_node_internal *) (p)
+
+#define dom_node_get_refcount(n) ((dom_node_internal *) (n))->refcnt
+
+dom_exception _redocument_lwcstring(lwc_context *old, lwc_context *new,
+ lwc_string **string);
+dom_exception _redocument_domstring(struct dom_document *old,
+ struct dom_document* new, struct dom_string **string);
+dom_exception _dom_merge_adjacent_text(dom_node_internal *p,
+ dom_node_internal *n);
+/* Used to extract the lwc_string from dom_string.
+ * If there is no lwc_string inside the param, create one use the node->owner
+ * as document */
+dom_exception _dom_node_get_intern_string(dom_node_internal *node,
+ struct dom_string *str, struct lwc_string_s **intern);
+void _dom_node_unref_intern_string(dom_node_internal *node,
+ struct lwc_string_s *inter);
+
+/* Try to destroy the node, if its refcnt is not zero, then append it to the
+ * owner document's pending list */
+void _dom_node_try_destroy(dom_node_internal *node);
+#define dom_node_try_destroy(n) _dom_node_try_destroy((dom_node_internal *) (n))
+
+/* To add some node to the pending list */
+void _dom_node_mark_pending(dom_node_internal *node);
+#define dom_node_mark_pending(n) _dom_node_mark_pending(\
+ (dom_node_internal *) (n))
+/* To remove the node from the pending list, this may happen when
+ * a node is removed and then appended to another parent */
+void _dom_node_remove_pending(dom_node_internal *node);
+#define dom_node_remove_pending(n) _dom_node_remove_pending(\
+ (dom_node_internal *) (n))
#endif
diff --git a/src/core/nodelist.c b/src/core/nodelist.c
index 16534b6..2497619 100644
--- a/src/core/nodelist.c
+++ b/src/core/nodelist.c
@@ -3,12 +3,17 @@
* Licensed under the MIT License,
* http://www.opensource.org/licenses/mit-license.php
* Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
*/
+#include <assert.h>
#include <dom/core/node.h>
+#include <dom/core/document.h>
#include <dom/core/nodelist.h>
#include <dom/core/string.h>
+#include <libwapcaplet/libwapcaplet.h>
+
#include "core/document.h"
#include "core/node.h"
#include "core/nodelist.h"
@@ -21,18 +26,22 @@
struct dom_nodelist {
struct dom_document *owner; /**< Owning document */
- struct dom_node_internal *root; /**< Root of applicable subtree */
+ struct dom_node_internal *root;
+ /**< Root of applicable subtree */
- enum { DOM_NODELIST_CHILDREN,
- DOM_NODELIST_BY_NAME,
- DOM_NODELIST_BY_NAMESPACE
- } type; /**< List type */
+ nodelist_type type; /**< Type of this list */
union {
- struct dom_string *name; /**< Tag name to match */
struct {
- struct dom_string *namespace; /**< Namespace */
- struct dom_string *localname; /**< Localname */
+ struct lwc_string_s *name;
+ /**< Tag name to match */
+ bool any_name; /**< The name is '*' */
+ } n;
+ struct {
+ bool any_namespace; /**< The namespace is '*' */
+ bool any_localname; /**< The localname is '*' */
+ struct lwc_string_s *namespace; /**< Namespace */
+ struct lwc_string_s *localname; /**< Localname */
} ns; /**< Data for namespace matching */
} data;
@@ -43,6 +52,7 @@ struct dom_nodelist {
* Create a nodelist
*
* \param doc Owning document
+ * \param type The type of the NodeList
* \param root Root node of subtree that list applies to
* \param tagname Name of nodes in list (or NULL)
* \param namespace Namespace part of nodes in list (or NULL)
@@ -52,27 +62,21 @@ struct dom_nodelist {
*
* ::root must be a node owned by ::doc
*
- * If ::tagname is non-NULL, ::namespace and ::localname must be NULL and
- * the created list will match nodes by name
- *
- * If ::namespace is non-NULL, ::localname must be non-NULL and
- * ::tagname must be NULL and the created list will match nodes by namespace
- * and localname
- *
- * If ::tagname, ::namespace and ::localname are NULL, the created list
- * will match the children of ::root.
- *
* The returned list will already be referenced, so the client need not
* do so explicitly. The client must unref the list once finished with it.
*/
-dom_exception dom_nodelist_create(struct dom_document *doc,
- struct dom_node_internal *root, struct dom_string *tagname,
- struct dom_string *namespace, struct dom_string *localname,
+dom_exception _dom_nodelist_create(struct dom_document *doc, nodelist_type type,
+ struct dom_node_internal *root, struct lwc_string_s *tagname,
+ struct lwc_string_s *namespace, struct lwc_string_s *localname,
struct dom_nodelist **list)
{
struct dom_nodelist *l;
+ lwc_context *ctx;
+
+ ctx = _dom_document_get_intern_context(doc);
+ assert(ctx != NULL);
- l = dom_document_alloc(doc, NULL, sizeof(struct dom_nodelist));
+ l = _dom_document_alloc(doc, NULL, sizeof(struct dom_nodelist));
if (l == NULL)
return DOM_NO_MEM_ERR;
@@ -82,20 +86,45 @@ dom_exception dom_nodelist_create(struct dom_document *doc,
dom_node_ref(root);
l->root = root;
- if (tagname != NULL && namespace == NULL && localname == NULL) {
- dom_string_ref(tagname);
- l->type = DOM_NODELIST_BY_NAME;
- l->data.name = tagname;
- } else if (namespace != NULL && localname != NULL &&
- tagname == NULL) {
- dom_string_ref(namespace);
- dom_string_ref(localname);
- l->type = DOM_NODELIST_BY_NAMESPACE;
+ l->type = type;
+
+ if (type == DOM_NODELIST_BY_NAME) {
+ assert(tagname != NULL);
+ l->data.n.any_name = false;
+ if (lwc_string_length(tagname) == 1) {
+ const char *ch = lwc_string_data(tagname);
+ if (*ch == '*') {
+ l->data.n.any_name = true;
+ }
+ }
+
+ lwc_context_string_ref(ctx, tagname);
+ l->data.n.name = tagname;
+ } else if (type == DOM_NODELIST_BY_NAMESPACE) {
+ l->data.ns.any_localname = false;
+ l->data.ns.any_namespace = false;
+ if (localname != NULL) {
+ if (lwc_string_length(localname) == 1) {
+ const char *ch = lwc_string_data(localname);
+ if (*ch == '*') {
+ l->data.ns.any_localname = true;
+ }
+ }
+ lwc_context_string_ref(ctx, localname);
+ }
+ if (namespace != NULL) {
+ if (lwc_string_length(namespace) == 1) {
+ const char *ch = lwc_string_data(namespace);
+ if (*ch == '*') {
+ l->data.ns.any_namespace = true;
+ }
+ }
+ lwc_context_string_ref(ctx, namespace);
+ }
+
l->data.ns.namespace = namespace;
l->data.ns.localname = localname;
- } else {
- l->type = DOM_NODELIST_CHILDREN;
- }
+ }
l->refcnt = 1;
@@ -111,6 +140,7 @@ dom_exception dom_nodelist_create(struct dom_document *doc,
*/
void dom_nodelist_ref(struct dom_nodelist *list)
{
+ assert(list != NULL);
list->refcnt++;
}
@@ -124,30 +154,41 @@ void dom_nodelist_ref(struct dom_nodelist *list)
*/
void dom_nodelist_unref(struct dom_nodelist *list)
{
+ if (list == NULL)
+ return;
+
if (--list->refcnt == 0) {
struct dom_node_internal *owner =
(struct dom_node_internal *) list->owner;
+ lwc_context *ctx;
+ ctx = _dom_document_get_intern_context((dom_document *) owner);
+ assert(ctx != NULL);
switch (list->type) {
case DOM_NODELIST_CHILDREN:
/* Nothing to do */
break;
case DOM_NODELIST_BY_NAMESPACE:
- dom_string_unref(list->data.ns.namespace);
- dom_string_unref(list->data.ns.localname);
+ if (list->data.ns.namespace != NULL)
+ lwc_context_string_unref(ctx,
+ list->data.ns.namespace);
+ if (list->data.ns.localname != NULL)
+ lwc_context_string_unref(ctx,
+ list->data.ns.localname);
break;
case DOM_NODELIST_BY_NAME:
- dom_string_unref(list->data.name);
+ assert(list->data.n.name != NULL);
+ lwc_context_string_unref(ctx, list->data.n.name);
break;
}
dom_node_unref(list->root);
/* Remove list from document */
- dom_document_remove_nodelist(list->owner, list);
+ _dom_document_remove_nodelist(list->owner, list);
/* Destroy the list object */
- dom_document_alloc(list->owner, list, 0);
+ _dom_document_alloc(list->owner, list, 0);
/* And release our reference on the owning document
* This must be last as, otherwise, it's possible that
@@ -175,19 +216,24 @@ dom_exception dom_nodelist_get_length(struct dom_nodelist *list,
if (list->type == DOM_NODELIST_CHILDREN) {
len++;
} else if (list->type == DOM_NODELIST_BY_NAME) {
- if (cur->name != NULL &&
- dom_string_cmp(cur->name,
- list->data.name) == 0) {
- len++;
+ /* Here, we compare two lwc_string pointer directly */
+ if (list->data.n.any_name == true || (
+ cur->name != NULL &&
+ cur->name == list->data.n.name)) {
+ if (cur->type == DOM_ELEMENT_NODE)
+ len++;
}
} else {
- if (cur->namespace != NULL &&
- dom_string_cmp(cur->namespace,
- list->data.ns.namespace) == 0 &&
- cur->name != NULL &&
- dom_string_cmp(cur->name,
- list->data.ns.localname) == 0) {
- len++;
+ if (list->data.ns.any_namespace == true ||
+ cur->namespace ==
+ list->data.ns.namespace) {
+ if (list->data.ns.any_localname == true ||
+ (cur->name != NULL &&
+ cur->name ==
+ list->data.ns.localname)) {
+ if (cur->type == DOM_ELEMENT_NODE)
+ len++;
+ }
}
}
@@ -250,19 +296,24 @@ dom_exception _dom_nodelist_item(struct dom_nodelist *list,
if (list->type == DOM_NODELIST_CHILDREN) {
count++;
} else if (list->type == DOM_NODELIST_BY_NAME) {
- if (cur->name != NULL &&
- dom_string_cmp(cur->name,
- list->data.name) == 0) {
- count++;
+ if (list->data.n.any_name == true || (
+ cur->name != NULL &&
+ cur->name == list->data.n.name)) {
+ if (cur->type == DOM_ELEMENT_NODE)
+ count++;
}
} else {
- if (cur->namespace != NULL &&
- dom_string_cmp(cur->namespace,
- list->data.ns.namespace) == 0 &&
- cur->name != NULL &&
- dom_string_cmp(cur->name,
- list->data.ns.localname) == 0) {
- count++;
+ if (list->data.ns.any_namespace == true ||
+ (cur->namespace != NULL &&
+ cur->namespace ==
+ list->data.ns.namespace)) {
+ if (list->data.ns.any_localname == true ||
+ (cur->name != NULL &&
+ cur->name ==
+ list->data.ns.localname)) {
+ if (cur->type == DOM_ELEMENT_NODE)
+ count++;
+ }
}
}
@@ -311,36 +362,49 @@ dom_exception _dom_nodelist_item(struct dom_nodelist *list,
* Match a nodelist instance against a set of nodelist creation parameters
*
* \param list List to match
+ * \param type The type of the NodeList
* \param root Root node of subtree that list applies to
* \param tagname Name of nodes in list (or NULL)
* \param namespace Namespace part of nodes in list (or NULL)
* \param localname Local part of nodes in list (or NULL)
* \return true if list matches, false otherwise
*/
-bool dom_nodelist_match(struct dom_nodelist *list,
- struct dom_node_internal *root, struct dom_string *tagname,
- struct dom_string *namespace, struct dom_string *localname)
+bool _dom_nodelist_match(struct dom_nodelist *list, nodelist_type type,
+ struct dom_node_internal *root, struct lwc_string_s *tagname,
+ struct lwc_string_s *namespace, struct lwc_string_s *localname)
{
if (list->root != root)
return false;
- if (list->type == DOM_NODELIST_CHILDREN && tagname == NULL &&
- namespace == NULL && localname == NULL) {
+ if (list->type != type)
+ return false;
+
+ if (list->type == DOM_NODELIST_CHILDREN) {
return true;
}
- if (list->type == DOM_NODELIST_BY_NAME && tagname != NULL &&
- namespace == NULL && localname == NULL) {
- return (dom_string_cmp(list->data.name, tagname) == 0);
+ if (list->type == DOM_NODELIST_BY_NAME) {
+ return (list->data.n.name == tagname);
}
- if (list->type == DOM_NODELIST_BY_NAMESPACE && tagname == NULL &&
- namespace != NULL && localname != NULL) {
- return (dom_string_cmp(list->data.ns.namespace,
- namespace) == 0) &&
- (dom_string_cmp(list->data.ns.localname,
- localname) == 0);
+ if (list->type == DOM_NODELIST_BY_NAMESPACE) {
+ return (list->data.ns.namespace == namespace) &&
+ (list->data.ns.localname == localname);
}
return false;
}
+
+/**
+ * Test whether the two NodeList are equal
+ *
+ * \param l1 One list
+ * \param l2 The other list
+ * \reutrn true for equal, false otherwise.
+ */
+bool _dom_nodelist_equal(struct dom_nodelist *l1, struct dom_nodelist *l2)
+{
+ return _dom_nodelist_match(l1, l1->type, l2->root, l2->data.n.name,
+ l2->data.ns.namespace, l2->data.ns.localname);
+}
+
diff --git a/src/core/nodelist.h b/src/core/nodelist.h
index 9629d03..e467aa6 100644
--- a/src/core/nodelist.h
+++ b/src/core/nodelist.h
@@ -16,16 +16,30 @@ struct dom_document;
struct dom_node;
struct dom_nodelist;
struct dom_string;
+struct lwc_string_s;
+
+/**
+ * The NodeList type
+ */
+typedef enum {
+ DOM_NODELIST_CHILDREN,
+ DOM_NODELIST_BY_NAME,
+ DOM_NODELIST_BY_NAMESPACE
+} nodelist_type;
/* Create a nodelist */
-dom_exception dom_nodelist_create(struct dom_document *doc,
- struct dom_node_internal *root, struct dom_string *tagname,
- struct dom_string *namespace, struct dom_string *localname,
+dom_exception _dom_nodelist_create(struct dom_document *doc, nodelist_type type,
+ struct dom_node_internal *root, struct lwc_string_s *tagname,
+ struct lwc_string_s *namespace, struct lwc_string_s *localname,
struct dom_nodelist **list);
/* Match a nodelist instance against a set of nodelist creation parameters */
-bool dom_nodelist_match(struct dom_nodelist *list,
- struct dom_node_internal *root, struct dom_string *tagname,
- struct dom_string *namespace, struct dom_string *localname);
+bool _dom_nodelist_match(struct dom_nodelist *list, nodelist_type type,
+ struct dom_node_internal *root, struct lwc_string_s *tagname,
+ struct lwc_string_s *namespace, struct lwc_string_s *localname);
+
+bool _dom_nodelist_equal(struct dom_nodelist *l1, struct dom_nodelist *l2);
+#define dom_nodelist_equal(l1, l2) _dom_nodelist_equal( \
+ (struct dom_nodelist *) (l1), (struct dom_nodelist *) (l2))
#endif
diff --git a/src/core/pi.c b/src/core/pi.c
index 754b362..634dc05 100644
--- a/src/core/pi.c
+++ b/src/core/pi.c
@@ -9,6 +9,8 @@
#include "core/node.h"
#include "core/pi.h"
+#include "utils/utils.h"
+
/**
* A DOM processing instruction
*/
@@ -16,6 +18,13 @@ struct dom_processing_instruction {
struct dom_node_internal base; /**< Base node */
};
+static struct dom_node_vtable pi_vtable = {
+ DOM_NODE_VTABLE
+};
+
+static struct dom_node_protect_vtable pi_protect_vtable = {
+ DOM_PI_PROTECT_VTABLE
+};
/**
* Create a processing instruction
*
@@ -30,25 +39,28 @@ struct dom_processing_instruction {
*
* The returned node will already be referenced.
*/
-dom_exception dom_processing_instruction_create(struct dom_document *doc,
- struct dom_string *name, struct dom_string *value,
+dom_exception _dom_processing_instruction_create(struct dom_document *doc,
+ struct lwc_string_s *name, struct dom_string *value,
struct dom_processing_instruction **result)
{
struct dom_processing_instruction *p;
dom_exception err;
/* Allocate the comment node */
- p = dom_document_alloc(doc, NULL,
+ p = _dom_document_alloc(doc, NULL,
sizeof(struct dom_processing_instruction));
if (p == NULL)
return DOM_NO_MEM_ERR;
+
+ p->base.base.vtable = &pi_vtable;
+ p->base.vtable = &pi_protect_vtable;
/* And initialise the node */
- err = dom_node_initialise(&p->base, doc,
+ err = _dom_processing_instruction_initialise(&p->base, doc,
DOM_PROCESSING_INSTRUCTION_NODE,
name, value, NULL, NULL);
if (err != DOM_NO_ERR) {
- dom_document_alloc(doc, p, 0);
+ _dom_document_alloc(doc, p, 0);
return err;
}
@@ -65,12 +77,49 @@ dom_exception dom_processing_instruction_create(struct dom_document *doc,
*
* The contents of ::pi will be destroyed and ::pi will be freed.
*/
-void dom_processing_instruction_destroy(struct dom_document *doc,
+void _dom_processing_instruction_destroy(struct dom_document *doc,
struct dom_processing_instruction *pi)
{
/* Finalise base class */
- dom_node_finalise(doc, &pi->base);
+ _dom_processing_instruction_finalise(doc, &pi->base);
/* Free processing instruction */
- dom_document_alloc(doc, pi, 0);
+ _dom_document_alloc(doc, pi, 0);
+}
+
+/*-----------------------------------------------------------------------*/
+
+/* Following comes the protected vtable */
+
+/* The virtual destroy function of this class */
+void _dom_pi_destroy(struct dom_node_internal *node)
+{
+ _dom_processing_instruction_destroy(node->owner,
+ (struct dom_processing_instruction *) node);
+}
+
+/* The memory allocator of this class */
+dom_exception _dom_pi_alloc(struct dom_document *doc,
+ struct dom_node_internal *n, struct dom_node_internal **ret)
+{
+ UNUSED(n);
+ struct dom_processing_instruction *a;
+
+ a = _dom_document_alloc(doc, NULL,
+ sizeof(struct dom_processing_instruction));
+ if (a == NULL)
+ return DOM_NO_MEM_ERR;
+
+ *ret = (dom_node_internal *) a;
+ dom_node_set_owner(*ret, doc);
+
+ return DOM_NO_ERR;
}
+
+/* The copy constructor of this class */
+dom_exception _dom_pi_copy(struct dom_node_internal *new,
+ struct dom_node_internal *old)
+{
+ return _dom_node_copy(new, old);
+}
+
diff --git a/src/core/pi.h b/src/core/pi.h
index 4dca989..3f6d46c 100644
--- a/src/core/pi.h
+++ b/src/core/pi.h
@@ -13,12 +13,28 @@
struct dom_document;
struct dom_processing_instruction;
struct dom_string;
+struct lwc_string_s;
-dom_exception dom_processing_instruction_create(struct dom_document *doc,
- struct dom_string *name, struct dom_string *value,
+dom_exception _dom_processing_instruction_create(struct dom_document *doc,
+ struct lwc_string_s *name, struct dom_string *value,
struct dom_processing_instruction **result);
-void dom_processing_instruction_destroy(struct dom_document *doc,
+void _dom_processing_instruction_destroy(struct dom_document *doc,
struct dom_processing_instruction *pi);
+#define _dom_processing_instruction_initialise _dom_node_initialise
+#define _dom_processing_instruction_finalise _dom_node_finalise
+
+/* Following comes the protected vtable */
+void _dom_pi_destroy(struct dom_node_internal *node);
+dom_exception _dom_pi_alloc(struct dom_document *doc,
+ struct dom_node_internal *n, struct dom_node_internal **ret);
+dom_exception _dom_pi_copy(struct dom_node_internal *new,
+ struct dom_node_internal *old);
+
+#define DOM_PI_PROTECT_VTABLE \
+ _dom_pi_destroy, \
+ _dom_pi_alloc, \
+ _dom_pi_copy
+
#endif
diff --git a/src/core/string.c b/src/core/string.c
index 806531a..e35f416 100644
--- a/src/core/string.c
+++ b/src/core/string.c
@@ -3,16 +3,17 @@
* Licensed under the MIT License,
* http://www.opensource.org/licenses/mit-license.php
* Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
*/
+#include <assert.h>
#include <ctype.h>
#include <inttypes.h>
#include <string.h>
#include <parserutils/charset/utf8.h>
-#include <dom/core/string.h>
-
+#include "core/string.h"
#include "core/document.h"
#include "utils/utils.h"
@@ -26,6 +27,10 @@ struct dom_string {
size_t len; /**< Byte length of string */
+ lwc_string *intern; /**< The lwc_string of this string */
+
+ lwc_context *context; /**< The lwc_context for the lwc_string */
+
dom_alloc alloc; /**< Memory (de)allocation function */
void *pw; /**< Client-specific data */
@@ -40,6 +45,8 @@ static struct dom_string empty_string = {
.refcnt = 1
};
+
+
/**
* Claim a reference on a DOM string
*
@@ -60,8 +67,15 @@ void dom_string_ref(struct dom_string *str)
*/
void dom_string_unref(struct dom_string *str)
{
+ if (str == NULL)
+ return;
+
if (--str->refcnt == 0) {
- if (str->alloc != NULL) {
+ if (str->intern != NULL) {
+ lwc_context_unref(str->context);
+ lwc_context_string_unref(str->context, str->intern);
+ str->alloc(str, 0, str->pw);
+ } else if (str->alloc != NULL) {
str->alloc(str->ptr, 0, str->pw);
str->alloc(str, 0, str->pw);
}
@@ -71,11 +85,11 @@ void dom_string_unref(struct dom_string *str)
/**
* Create a DOM string from a string of characters
*
- * \param alloc Memory (de)allocation function
- * \param pw Pointer to client-specific private data
- * \param ptr Pointer to string of characters
- * \param len Length, in bytes, of string of characters
- * \param str Pointer to location to receive result
+ * \param alloc Memory (de)allocation function
+ * \param pw Pointer to client-specific private data
+ * \param ptr Pointer to string of characters
+ * \param len Length, in bytes, of string of characters
+ * \param str Pointer to location to receive result
* \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion
*
* The returned string will already be referenced, so there is no need
@@ -89,7 +103,7 @@ dom_exception dom_string_create(dom_alloc alloc, void *pw,
{
struct dom_string *ret;
- if (ptr == NULL && len == 0) {
+ if (ptr == NULL || len == 0) {
dom_string_ref(&empty_string);
*str = &empty_string;
@@ -114,6 +128,9 @@ dom_exception dom_string_create(dom_alloc alloc, void *pw,
ret->alloc = alloc;
ret->pw = pw;
+ ret->intern = NULL;
+ ret->context = NULL;
+
ret->refcnt = 1;
*str = ret;
@@ -122,6 +139,152 @@ dom_exception dom_string_create(dom_alloc alloc, void *pw,
}
/**
+ * Clone a dom_string if necessary. This method is used to create a new string
+ * with a new allocator, but if the allocator is the same with the paramter
+ * str, just ref the string.
+ *
+ * \param alloc The new allocator for this string
+ * \param pw The new pw for this string
+ * \param str The source dom_string
+ * \param ret The cloned dom_string
+ * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion
+ *
+ * @note: When both the alloc and pw are the same as the str's, we need no
+ * real clone, just ref the source string is ok.
+ */
+dom_exception dom_string_clone(dom_alloc alloc, void *pw,
+ struct dom_string *str, struct dom_string **ret)
+{
+ if (alloc == str->alloc && pw == str->pw) {
+ *ret = str;
+ dom_string_ref(str);
+ return DOM_NO_ERR;
+ }
+
+ if (str->intern != NULL) {
+ return _dom_string_create_from_lwcstring(alloc, pw,
+ str->context, str->intern, ret);
+ } else {
+ return dom_string_create(alloc, pw, str->ptr, str->len, ret);
+ }
+}
+
+/**
+ * Create a dom_string from a lwc_string
+ *
+ * \param ctx The lwc_context
+ * \param str The lwc_string
+ * \param ret The new dom_string
+ * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion
+ */
+dom_exception _dom_string_create_from_lwcstring(dom_alloc alloc, void *pw,
+ lwc_context *ctx, lwc_string *str, struct dom_string **ret)
+{
+ dom_string *r;
+
+ if (str == NULL) {
+ *ret = NULL;
+ return DOM_NO_ERR;
+ }
+
+ r = alloc(NULL, sizeof(struct dom_string), pw);
+ if (r == NULL)
+ return DOM_NO_MEM_ERR;
+
+ if (str == NULL) {
+ *ret = &empty_string;
+ dom_string_ref(*ret);
+ return DOM_NO_ERR;
+ }
+
+ r->context = ctx;
+ r->intern = str;
+ r->ptr = (uint8_t *)lwc_string_data(str);
+ r->len = lwc_string_length(str);
+
+ r->alloc = alloc;
+ r->pw = pw;
+
+ r->refcnt = 1;
+
+ /* Ref the lwc_string */
+ lwc_context_ref(ctx);
+ lwc_context_string_ref(ctx, str);
+
+ *ret = r;
+ return DOM_NO_ERR;
+
+}
+
+/**
+ * Make the dom_string be interned in the lwc_context
+ *
+ * \param str The dom_string to be interned
+ * \param ctx The lwc_context to intern this dom_string
+ * \param lwcstr The result lwc_string
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ */
+dom_exception _dom_string_intern(struct dom_string *str,
+ struct lwc_context_s *ctx, struct lwc_string_s **lwcstr)
+{
+ lwc_string *ret;
+ lwc_error lerr;
+
+ /* If this string is interned with the same context, do nothing */
+ if (str->context != NULL && str->context == ctx) {
+ *lwcstr = str->intern;
+ return DOM_NO_ERR;
+ }
+
+ lerr = lwc_context_intern(ctx, (const char *)str->ptr, str->len, &ret);
+ if (lerr != lwc_error_ok) {
+ return _dom_exception_from_lwc_error(lerr);
+ }
+
+ if (str->context != NULL) {
+ lwc_context_unref(str->context);
+ lwc_context_string_unref(str->context, str->intern);
+ str->ptr = NULL;
+ }
+
+ str->context = ctx;
+ str->intern = ret;
+ lwc_context_ref(ctx);
+ lwc_context_string_ref(ctx, ret);
+
+ if (str->ptr != NULL) {
+ str->alloc(str->ptr, 0, str->pw);
+ }
+
+ str->ptr = (uint8_t *) lwc_string_data(ret);
+
+ *lwcstr = ret;
+ return DOM_NO_ERR;
+}
+
+/**
+ * Get the internal lwc_string
+ *
+ * \param str The dom_string object
+ * \param ctx The lwc_context which intern this dom_string
+ * \param lwcstr The lwc_string of this dom-string
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ */
+dom_exception dom_string_get_intern(struct dom_string *str,
+ struct lwc_context_s **ctx, struct lwc_string_s **lwcstr)
+{
+ *ctx = str->context;
+ *lwcstr = str->intern;
+
+ if (*ctx != NULL)
+ lwc_context_ref(*ctx);
+ if (*lwcstr != NULL)
+ lwc_context_string_ref(*ctx, *lwcstr);
+
+ return DOM_NO_ERR;
+}
+
+/**
* Case sensitively compare two DOM strings
*
* \param s1 The first string to compare
@@ -132,12 +295,26 @@ dom_exception dom_string_create(dom_alloc alloc, void *pw,
*/
int dom_string_cmp(struct dom_string *s1, struct dom_string *s2)
{
+ bool ret;
+
if (s1 == NULL)
s1 = &empty_string;
if (s2 == NULL)
s2 = &empty_string;
+ if (s1->context == s2->context && s1->context != NULL) {
+ assert(s1->intern != NULL);
+ assert(s2->intern != NULL);
+ lwc_context_string_isequal(s1->context, s1->intern,
+ s2->intern, &ret);
+ if (ret == true) {
+ return 0;
+ } else {
+ return -1;
+ }
+ }
+
if (s1->len != s2->len)
return 1;
@@ -164,6 +341,19 @@ int dom_string_icmp(struct dom_string *s1, struct dom_string *s2)
if (s2 == NULL)
s2 = &empty_string;
+ bool ret;
+ if (s1->context == s2->context && s1->context != NULL) {
+ assert(s1->intern != NULL);
+ assert(s2->intern != NULL);
+ lwc_context_string_caseless_isequal(s1->context, s1->intern,
+ s2->intern, &ret);
+ if (ret == true) {
+ return 0;
+ } else {
+ return -1;
+ }
+ }
+
d1 = s1->ptr;
d2 = s2->ptr;
l1 = s1->len;
@@ -304,6 +494,56 @@ uint32_t dom_string_length(struct dom_string *str)
return clen;
}
+/**
+ * Get the UCS4 character at position index
+ *
+ * \param index The position of the charater
+ * \param ch The UCS4 character
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ */
+dom_exception dom_string_at(struct dom_string *str, uint32_t index,
+ uint32_t *ch)
+{
+ const uint8_t *s;
+ size_t clen, slen;
+ uint32_t c, i;
+ parserutils_error err;
+
+ if (str == NULL)
+ str = &empty_string;
+
+ s = str->ptr;
+ slen = str->len;
+
+ i = 0;
+
+ while (slen > 0) {
+ err = parserutils_charset_utf8_char_byte_length(s, &clen);
+ if (err != PARSERUTILS_OK) {
+ return (uint32_t) -1;
+ }
+
+ i++;
+ if (i == index + 1)
+ break;
+
+ s += clen;
+ slen -= clen;
+ }
+
+ if (i == index + 1) {
+ err = parserutils_charset_utf8_to_ucs4(s, slen, &c, &clen);
+ if (err != PARSERUTILS_OK) {
+ return (uint32_t) -1;
+ }
+
+ *ch = c;
+ return DOM_NO_ERR;
+ } else {
+ return DOM_DOMSTRING_SIZE_ERR;
+ }
+}
+
/**
* Concatenate two dom strings
*
@@ -322,16 +562,33 @@ dom_exception dom_string_concat(struct dom_string *s1, struct dom_string *s2,
struct dom_string **result)
{
struct dom_string *concat;
+ dom_alloc alloc;
+ void *pw;
+
+ assert(s1 != NULL);
+ assert(s2 != NULL);
+
+ if (s1->alloc != NULL) {
+ alloc = s1->alloc;
+ pw = s1->pw;
+ } else if (s2->alloc != NULL) {
+ alloc = s2->alloc;
+ pw = s2->pw;
+ } else {
+ /* s1 == s2 == empty_string */
+ *result = &empty_string;
+ return DOM_NO_ERR;
+ }
- concat = s1->alloc(NULL, sizeof(struct dom_string), s1->pw);
+ concat = alloc(NULL, sizeof(struct dom_string), pw);
if (concat == NULL) {
return DOM_NO_MEM_ERR;
}
- concat->ptr = s1->alloc(NULL, s1->len + s2->len, s1->pw);
+ concat->ptr = alloc(NULL, s1->len + s2->len, pw);
if (concat->ptr == NULL) {
- s1->alloc(concat, 0, s1->pw);
+ alloc(concat, 0, pw);
return DOM_NO_MEM_ERR;
}
@@ -342,8 +599,10 @@ dom_exception dom_string_concat(struct dom_string *s1, struct dom_string *s2,
concat->len = s1->len + s2->len;
- concat->alloc = s1->alloc;
- concat->pw = s1->pw;
+ concat->alloc = alloc;
+ concat->pw = pw;
+ concat->context = NULL;
+ concat->intern = NULL;
concat->refcnt = 1;
@@ -382,7 +641,7 @@ dom_exception dom_string_substr(struct dom_string *str,
/* Calculate the byte index of the start */
while (i1 > 0) {
- err = parserutils_charset_utf8_next(s, slen - b1, b1, &b1);
+ err = parserutils_charset_utf8_next(s, slen, b1, &b1);
if (err != PARSERUTILS_OK) {
return DOM_NO_MEM_ERR;
}
@@ -395,7 +654,7 @@ dom_exception dom_string_substr(struct dom_string *str,
/* Calculate the byte index of the end */
while (i2 > 0) {
- err = parserutils_charset_utf8_next(s, slen - b2, b2, &b2);
+ err = parserutils_charset_utf8_next(s, slen, b2, &b2);
if (err != PARSERUTILS_OK) {
return DOM_NO_MEM_ERR;
}
@@ -451,7 +710,7 @@ dom_exception dom_string_insert(struct dom_string *target,
ins = tlen;
} else {
while (offset > 0) {
- err = parserutils_charset_utf8_next(t, tlen - ins,
+ err = parserutils_charset_utf8_next(t, tlen,
ins, &ins);
if (err != PARSERUTILS_OK) {
@@ -492,6 +751,8 @@ dom_exception dom_string_insert(struct dom_string *target,
res->alloc = target->alloc;
res->pw = target->pw;
+ res->intern = NULL;
+ res->context = NULL;
res->refcnt = 1;
@@ -526,6 +787,9 @@ dom_exception dom_string_replace(struct dom_string *target,
uint32_t b1, b2;
parserutils_error err;
+ if (source == NULL)
+ source = &empty_string;
+
t = target->ptr;
tlen = target->len;
s = source->ptr;
@@ -538,7 +802,7 @@ dom_exception dom_string_replace(struct dom_string *target,
/* Calculate the byte index of the start */
while (i1 > 0) {
- err = parserutils_charset_utf8_next(s, slen - b1, b1, &b1);
+ err = parserutils_charset_utf8_next(s, slen, b1, &b1);
if (err != PARSERUTILS_OK) {
return DOM_NO_MEM_ERR;
@@ -552,7 +816,7 @@ dom_exception dom_string_replace(struct dom_string *target,
/* Calculate the byte index of the end */
while (i2 > 0) {
- err = parserutils_charset_utf8_next(s, slen - b2, b2, &b2);
+ err = parserutils_charset_utf8_next(s, slen, b2, &b2);
if (err != PARSERUTILS_OK) {
return DOM_NO_MEM_ERR;
@@ -594,6 +858,8 @@ dom_exception dom_string_replace(struct dom_string *target,
res->alloc = target->alloc;
res->pw = target->pw;
+ res->intern = NULL;
+ res->context = NULL;
res->refcnt = 1;
@@ -618,8 +884,13 @@ dom_exception dom_string_replace(struct dom_string *target,
dom_exception dom_string_dup(struct dom_string *str,
struct dom_string **result)
{
- return dom_string_create(str->alloc, str->pw, str->ptr, str->len,
- result);
+ if (str->intern != NULL) {
+ return _dom_string_create_from_lwcstring(str->alloc, str->pw,
+ str->context, str->intern, result);
+ } else {
+ return dom_string_create(str->alloc, str->pw, str->ptr,
+ str->len, result);
+ }
}
/**
@@ -645,3 +916,48 @@ uint32_t dom_string_hash(struct dom_string *str)
return hash;
}
+/**
+ * Convert a lwc_error to a dom_exception
+ *
+ * \param err The input lwc_error
+ * \return the dom_exception
+ */
+dom_exception _dom_exception_from_lwc_error(lwc_error err)
+{
+ switch (err) {
+ case lwc_error_ok:
+ return DOM_NO_ERR;
+ case lwc_error_oom:
+ return DOM_NO_MEM_ERR;
+ case lwc_error_range:
+ return DOM_INDEX_SIZE_ERR;
+ }
+ assert ("Unknow lwc_error, can't convert to dom_exception");
+ /* Suppress compile errors */
+ return DOM_NO_ERR;
+}
+
+/**
+ * Compare the raw data of two lwc_strings for equality when the two strings
+ * belong to different lwc_context
+ *
+ * \param s1 The first lwc_string
+ * \param s2 The second lwc_string
+ * \return 0 for equal, non-zero otherwise
+ */
+int _dom_lwc_string_compare_raw(struct lwc_string_s *s1,
+ struct lwc_string_s *s2)
+{
+ const char *rs1, *rs2;
+ size_t len;
+
+ if (lwc_string_length(s1) != lwc_string_length(s2))
+ return -1;
+
+ len = lwc_string_length(s1);
+ rs1 = lwc_string_data(s1);
+ rs2 = lwc_string_data(s2);
+
+ return memcmp(rs1, rs2, len);
+}
+
diff --git a/src/core/string.h b/src/core/string.h
new file mode 100644
index 0000000..8372688
--- /dev/null
+++ b/src/core/string.h
@@ -0,0 +1,32 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
+ */
+
+#ifndef dom_internal_core_string_h_
+#define dom_internal_core_string_h_
+
+#include <dom/core/string.h>
+
+/* Create a DOM string from a lwc_string
+ * This function call mainly used for create a string from lwc_string */
+dom_exception _dom_string_create_from_lwcstring(dom_alloc alloc, void *pw,
+ struct lwc_context_s *ctx, struct lwc_string_s *str,
+ struct dom_string **ret);
+
+/* Make the dom_string be interned in the lwc_context */
+dom_exception _dom_string_intern(struct dom_string *str,
+ struct lwc_context_s *ctx, struct lwc_string_s **lwcstr);
+
+/* Compare the raw data of two lwc_strings for equality when the two strings
+ * belong to different lwc_context */
+int _dom_lwc_string_compare_raw(struct lwc_string_s *s1,
+ struct lwc_string_s *s2);
+
+/* Map the lwc_error to dom_exception */
+dom_exception _dom_exception_from_lwc_error(lwc_error err);
+
+#endif
+
diff --git a/src/core/text.c b/src/core/text.c
index bad20bf..6cb9e1f 100644
--- a/src/core/text.c
+++ b/src/core/text.c
@@ -3,18 +3,23 @@
* Licensed under the MIT License,
* http://www.opensource.org/licenses/mit-license.php
* Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
*/
+#include <assert.h>
+
#include <dom/core/string.h>
#include <dom/core/text.h>
+#include <libwapcaplet/libwapcaplet.h>
+
#include "core/characterdata.h"
#include "core/document.h"
#include "core/text.h"
#include "utils/utils.h"
/* The virtual table for dom_text */
-static struct dom_text_vtable text_vtable = {
+struct dom_text_vtable text_vtable = {
{
{
DOM_NODE_VTABLE
@@ -24,15 +29,30 @@ static struct dom_text_vtable text_vtable = {
DOM_TEXT_VTABLE
};
-/* The destroy virtual function */
-void _dom_text_destroy(struct dom_node_internal *node);
-void _dom_text_destroy(struct dom_node_internal *node)
-{
- struct dom_document *doc;
- dom_node_get_owner_document(node, &doc);
+static struct dom_node_protect_vtable text_protect_vtable = {
+ DOM_TEXT_PROTECT_VTABLE
+};
- dom_text_destroy(doc, (struct dom_text *) node);
-}
+/* Following comes helper functions */
+typedef enum walk_operation {
+ COLLECT,
+ DELETE
+} walk_operation;
+typedef enum walk_order {
+ LEFT,
+ RIGHT
+} walk_order;
+
+/* Walk the logic-adjacent text in document order */
+static dom_exception walk_logic_adjacent_text_in_order(
+ dom_node_internal *node, walk_operation opt,
+ walk_order order, dom_string **ret, bool *cont);
+/* Walk the logic-adjacent text */
+static dom_exception walk_logic_adjacent_text(dom_text *text,
+ walk_operation opt, dom_string **ret);
+
+/*----------------------------------------------------------------------*/
+/* Constructor and Destructor */
/**
* Create a text node
@@ -48,25 +68,29 @@ void _dom_text_destroy(struct dom_node_internal *node)
*
* The returned node will already be referenced.
*/
-dom_exception dom_text_create(struct dom_document *doc,
- struct dom_string *name, struct dom_string *value,
+dom_exception _dom_text_create(struct dom_document *doc,
+ struct lwc_string_s *name, struct dom_string *value,
struct dom_text **result)
{
struct dom_text *t;
dom_exception err;
/* Allocate the text node */
- t = dom_document_alloc(doc, NULL, sizeof(struct dom_text));
+ t = _dom_document_alloc(doc, NULL, sizeof(struct dom_text));
if (t == NULL)
return DOM_NO_MEM_ERR;
/* And initialise the node */
- err = dom_text_initialise(t, doc, DOM_TEXT_NODE, name, value);
+ err = _dom_text_initialise(t, doc, DOM_TEXT_NODE, name, value);
if (err != DOM_NO_ERR) {
- dom_document_alloc(doc, t, 0);
+ _dom_document_alloc(doc, t, 0);
return err;
}
+ /* Compose the vtable */
+ ((struct dom_node *) t)->vtable = &text_vtable;
+ ((struct dom_node_internal *) t)->vtable = &text_protect_vtable;
+
*result = t;
return DOM_NO_ERR;
@@ -80,13 +104,13 @@ dom_exception dom_text_create(struct dom_document *doc,
*
* The contents of ::text will be destroyed and ::text will be freed.
*/
-void dom_text_destroy(struct dom_document *doc, struct dom_text *text)
+void _dom_text_destroy(struct dom_document *doc, struct dom_text *text)
{
/* Finalise node */
- dom_text_finalise(doc, text);
+ _dom_text_finalise(doc, text);
/* Free node */
- dom_document_alloc(doc, text, 0);
+ _dom_document_alloc(doc, text, 0);
}
/**
@@ -101,22 +125,18 @@ void dom_text_destroy(struct dom_document *doc, struct dom_text *text)
*
* ::doc, ::name and ::value will have their reference counts increased.
*/
-dom_exception dom_text_initialise(struct dom_text *text,
+dom_exception _dom_text_initialise(struct dom_text *text,
struct dom_document *doc, dom_node_type type,
- struct dom_string *name, struct dom_string *value)
+ struct lwc_string_s *name, struct dom_string *value)
{
dom_exception err;
/* Initialise the base class */
- err = dom_characterdata_initialise(&text->base, doc, type,
+ err = _dom_characterdata_initialise(&text->base, doc, type,
name, value);
if (err != DOM_NO_ERR)
return err;
- /* Compose the vtable */
- ((struct dom_node *) text)->vtable = &text_vtable;
- text->base.base.destroy = &_dom_text_destroy;
-
/* Perform our type-specific initialisation */
text->element_content_whitespace = false;
@@ -131,11 +151,14 @@ dom_exception dom_text_initialise(struct dom_text *text,
*
* The contents of ::text will be cleaned up. ::text will not be freed.
*/
-void dom_text_finalise(struct dom_document *doc, struct dom_text *text)
+void _dom_text_finalise(struct dom_document *doc, struct dom_text *text)
{
- dom_characterdata_finalise(doc, &text->base);
+ _dom_characterdata_finalise(doc, &text->base);
}
+/*----------------------------------------------------------------------*/
+/* The public virtual functions */
+
/**
* Split a text node at a given character offset
*
@@ -181,7 +204,7 @@ dom_exception _dom_text_split_text(struct dom_text *text,
}
/* Create new node */
- err = dom_text_create(t->owner, t->name, value, &res);
+ err = _dom_text_create(t->owner, t->name, value, &res);
if (err != DOM_NO_ERR) {
dom_string_unref(value);
return err;
@@ -227,10 +250,7 @@ dom_exception _dom_text_get_is_element_content_whitespace(
dom_exception _dom_text_get_whole_text(struct dom_text *text,
struct dom_string **result)
{
- UNUSED(text);
- UNUSED(result);
-
- return DOM_NOT_SUPPORTED_ERR;
+ return walk_logic_adjacent_text(text, COLLECT, result);
}
/**
@@ -249,10 +269,240 @@ dom_exception _dom_text_get_whole_text(struct dom_text *text,
dom_exception _dom_text_replace_whole_text(struct dom_text *text,
struct dom_string *content, struct dom_text **result)
{
- UNUSED(text);
- UNUSED(content);
- UNUSED(result);
+ dom_exception err;
+ dom_string *ret;
+
+ err = walk_logic_adjacent_text(text, DELETE, &ret);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ err = dom_characterdata_set_data(text, content);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ *result = text;
+ dom_node_ref(text);
+
+ return DOM_NO_ERR;
+}
+
+/*-----------------------------------------------------------------------*/
+/* The protected virtual functions */
+
+/* The destroy function of this class */
+void __dom_text_destroy(struct dom_node_internal *node)
+{
+ struct dom_document *doc;
+ doc = dom_node_get_owner(node);
+
+ _dom_text_destroy(doc, (struct dom_text *) node);
+}
+
+/* The memory allocator for this class */
+dom_exception _dom_text_alloc(struct dom_document *doc,
+ struct dom_node_internal *n, struct dom_node_internal **ret)
+{
+ UNUSED(n);
+ dom_text *a;
+
+ a = _dom_document_alloc(doc, NULL, sizeof(struct dom_text));
+ if (a == NULL)
+ return DOM_NO_MEM_ERR;
+
+ *ret = (dom_node_internal *) a;
+ dom_node_set_owner(*ret, doc);
+
+ return DOM_NO_ERR;
+}
+
+/* The copy constructor of this class */
+dom_exception _dom_text_copy(struct dom_node_internal *new,
+ struct dom_node_internal *old)
+{
+ dom_text *ot = (dom_text *) old;
+ dom_text *nt = (dom_text *) new;
- return DOM_NOT_SUPPORTED_ERR;
+ nt->element_content_whitespace = ot->element_content_whitespace;
+
+ return _dom_characterdata_copy(new, old);
+}
+
+/*----------------------------------------------------------------------*/
+/* Helper functions */
+
+/**
+ * Walk the logic adjacent text in certain order
+ *
+ * \param node The start Text node
+ * \param opt The operation on each Text Node
+ * \param order The order
+ * \param ret The string of the logic adjacent text
+ * \param cont Whether the logic adjacent text is interrupt here
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ */
+dom_exception walk_logic_adjacent_text_in_order(
+ dom_node_internal *node, walk_operation opt,
+ walk_order order, dom_string **ret, bool *cont)
+{
+ dom_exception err;
+ dom_string *data, *tmp;
+ dom_node_internal *parent = dom_node_get_parent(node);
+
+ /* If we reach the leaf of the DOM tree, just return to continue
+ * to next sibling of our parent */
+ if (node == NULL) {
+ *cont = true;
+ return DOM_NO_ERR;
+ }
+
+ while (node != NULL) {
+ /* If we reach the boundary of logical-adjacent text, we stop */
+ if (node->type == DOM_ELEMENT_NODE ||
+ node->type == DOM_COMMENT_NODE ||
+ node->type ==
+ DOM_PROCESSING_INSTRUCTION_NODE) {
+ *cont = false;
+ return DOM_NO_ERR;
+ }
+
+ if (node->type == DOM_TEXT_NODE) {
+ /* According the DOM spec, text node never have child */
+ assert(node->first_child == NULL);
+ assert(node->last_child == NULL);
+ if (opt == COLLECT) {
+ err = dom_characterdata_get_data(node, &data);
+ if (err == DOM_NO_ERR)
+ return err;
+
+ tmp = *ret;
+ if (order == LEFT) {
+ err = dom_string_concat(data, tmp, ret);
+ if (err == DOM_NO_ERR)
+ return err;
+ } else if (order == RIGHT) {
+ err = dom_string_concat(tmp, data, ret);
+ if (err == DOM_NO_ERR)
+ return err;
+ }
+
+ dom_string_unref(tmp);
+ dom_string_unref(data);
+
+ *cont = true;
+ return DOM_NO_ERR;
+ }
+
+ if (opt == DELETE) {
+ dom_node_internal *tn;
+ err = dom_node_remove_child(node->parent,
+ node, (void *) &tn);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ *cont = true;
+ dom_node_unref(tn);
+ return DOM_NO_ERR;
+ }
+ }
+
+ dom_node_internal *p = dom_node_get_parent(node);
+ if (order == LEFT) {
+ if (node->last_child != NULL) {
+ node = node->last_child;
+ } else if (node->previous != NULL) {
+ node = node->previous;
+ } else {
+ while (p != parent && node == p->last_child) {
+ node = p;
+ p = dom_node_get_parent(p);
+ }
+
+ node = node->previous;
+ }
+ } else {
+ if (node->first_child != NULL) {
+ node = node->first_child;
+ } else if (node->next != NULL) {
+ node = node->next;
+ } else {
+ while (p != parent && node == p->first_child) {
+ node = p;
+ p = dom_node_get_parent(p);
+ }
+
+ node = node->next;
+ }
+ }
+ }
+
+ return DOM_NO_ERR;
+}
+
+/**
+ * Traverse the logic adjacent text.
+ *
+ * \param text The Text Node from which we start traversal
+ * \param opt The operation code
+ * \param ret The returned string if the opt is COLLECT
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ */
+dom_exception walk_logic_adjacent_text(dom_text *text,
+ walk_operation opt, dom_string **ret)
+{
+ dom_node_internal *node = (dom_node_internal *) text;
+ dom_node_internal *parent = node->parent;
+ dom_node_internal *left = node->previous;
+ dom_node_internal *right = node->next;
+ dom_exception err;
+ bool cont;
+
+ if (parent->type == DOM_ENTITY_NODE) {
+ return DOM_NOT_SUPPORTED_ERR;
+ }
+
+ /* Firstly, we look our left */
+ err = walk_logic_adjacent_text_in_order(left, opt, LEFT, ret, &cont);
+ if (err != DOM_NO_ERR) {
+ dom_string_unref(*ret);
+ *ret = NULL;
+ return err;
+ }
+
+ /* Ourself */
+ if (opt == COLLECT) {
+ dom_string *data = NULL, *tmp = NULL;
+ err = dom_characterdata_get_data(text, &data);
+ if (err == DOM_NO_ERR) {
+ dom_string_unref(*ret);
+ return err;
+ }
+
+ err = dom_string_concat(*ret, data, &tmp);
+ if (err == DOM_NO_ERR) {
+ dom_string_unref(*ret);
+ return err;
+ }
+
+ dom_string_unref(*ret);
+ dom_string_unref(data);
+ *ret = tmp;
+ } else {
+ dom_node_internal *tn;
+ err = dom_node_remove_child(node->parent, node,
+ (void *) &tn);
+ if (err != DOM_NO_ERR)
+ return err;
+ dom_node_unref(tn);
+ }
+
+ /* Now, look right */
+ err = walk_logic_adjacent_text_in_order(right, opt, RIGHT, ret, &cont);
+ if (err != DOM_NO_ERR) {
+ dom_string_unref(*ret);
+ *ret = NULL;
+ return err;
+ }
+
+ return DOM_NO_ERR;
}
diff --git a/src/core/text.h b/src/core/text.h
index faf88cc..e5de56c 100644
--- a/src/core/text.h
+++ b/src/core/text.h
@@ -16,6 +16,8 @@
struct dom_document;
struct dom_string;
+struct lwc_context_s;
+struct lwc_string_s;
/**
* A DOM text node
@@ -27,7 +29,21 @@ struct dom_text {
* content whitespace */
};
-/* Vitual functions for dom_text */
+/* Constructor and Destructor */
+dom_exception _dom_text_create(struct dom_document *doc,
+ struct lwc_string_s *name, struct dom_string *value,
+ struct dom_text **result);
+
+void _dom_text_destroy(struct dom_document *doc, struct dom_text *text);
+
+dom_exception _dom_text_initialise(struct dom_text *text,
+ struct dom_document *doc, dom_node_type type,
+ struct lwc_string_s *name, struct dom_string *value);
+
+void _dom_text_finalise(struct dom_document *doc, struct dom_text *text);
+
+
+/* Virtual functions for dom_text */
dom_exception _dom_text_split_text(struct dom_text *text,
unsigned long offset, struct dom_text **result);
dom_exception _dom_text_get_is_element_content_whitespace(
@@ -37,22 +53,26 @@ dom_exception _dom_text_get_whole_text(struct dom_text *text,
dom_exception _dom_text_replace_whole_text(struct dom_text *text,
struct dom_string *content, struct dom_text **result);
-dom_exception dom_text_create(struct dom_document *doc,
- struct dom_string *name, struct dom_string *value,
- struct dom_text **result);
-
-void dom_text_destroy(struct dom_document *doc, struct dom_text *text);
-
-dom_exception dom_text_initialise(struct dom_text *text,
- struct dom_document *doc, dom_node_type type,
- struct dom_string *name, struct dom_string *value);
-
-void dom_text_finalise(struct dom_document *doc, struct dom_text *text);
-
#define DOM_TEXT_VTABLE \
_dom_text_split_text, \
_dom_text_get_is_element_content_whitespace, \
_dom_text_get_whole_text, \
_dom_text_replace_whole_text
+
+/* Following comes the protected vtable */
+void __dom_text_destroy(struct dom_node_internal *node);
+dom_exception _dom_text_alloc(struct dom_document *doc,
+ struct dom_node_internal *n, struct dom_node_internal **ret);
+dom_exception _dom_text_copy(struct dom_node_internal *new,
+ struct dom_node_internal *old);
+
+#define DOM_TEXT_PROTECT_VTABLE \
+ __dom_text_destroy, \
+ _dom_text_alloc, \
+ _dom_text_copy
+
+
+extern struct dom_text_vtable text_vtable;
+
#endif
diff --git a/src/core/typeinfo.c b/src/core/typeinfo.c
new file mode 100644
index 0000000..4ebefcd
--- /dev/null
+++ b/src/core/typeinfo.c
@@ -0,0 +1,80 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
+ */
+
+#include <dom/core/typeinfo.h>
+#include <dom/core/string.h>
+
+#include "utils/utils.h"
+
+/* TypeInfo object */
+struct dom_type_info {
+ struct lwc_string_s *type; /**< Type name */
+ struct lwc_string_s *namespace; /**< Type namespace */
+};
+
+/**
+ * Get the type name of this dom_type_info
+ *
+ * \param ti The dom_type_info
+ * \param ret The name
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ *
+ * We don't support this API now, so this function call always
+ * return DOM_NOT_SUPPORTED_ERR.
+ */
+dom_exception _dom_type_info_get_type_name(dom_type_info *ti,
+ struct dom_string **ret)
+{
+ UNUSED(ti);
+ UNUSED(ret);
+
+ return DOM_NOT_SUPPORTED_ERR;
+}
+
+/**
+ * Get the namespace of this type info
+ *
+ * \param ti The dom_type_info
+ * \param ret The namespace
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ *
+ * We don't support this API now, so this function call always
+ * return DOM_NOT_SUPPORTED_ERR.
+ */
+dom_exception _dom_type_info_get_type_namespace(dom_type_info *ti,
+ struct dom_string **ret)
+{
+ UNUSED(ti);
+ UNUSED(ret);
+ return DOM_NOT_SUPPORTED_ERR;
+}
+
+/**
+ * Whether this type info is derived from another one
+ *
+ * \param ti The dom_type_info
+ * \param namespace The namespace of name
+ * \param name The name of the base typeinfo
+ * \param method The deriving method
+ * \param ret The return value
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ *
+ * We don't support this API now, so this function call always
+ * return DOM_NOT_SUPPORTED_ERR.
+ */
+dom_exception _dom_type_info_is_derived(dom_type_info *ti,
+ struct dom_string *namespace, struct dom_string *name,
+ dom_type_info_derivation_method method, bool *ret)
+{
+ UNUSED(ti);
+ UNUSED(namespace);
+ UNUSED(name);
+ UNUSED(method);
+ UNUSED(ret);
+ return DOM_NOT_SUPPORTED_ERR;
+}
+
diff --git a/src/utils/Makefile b/src/utils/Makefile
index c80f261..428a9cf 100644
--- a/src/utils/Makefile
+++ b/src/utils/Makefile
@@ -1,4 +1,5 @@
# Sources
-DIR_SOURCES := namespace.c
+DIR_SOURCES := namespace.c hashtable.c resource_mgr.c character_valid.c \
+ validate.c
include build/makefiles/Makefile.subdir
diff --git a/src/utils/character_valid.c b/src/utils/character_valid.c
new file mode 100644
index 0000000..2251075
--- /dev/null
+++ b/src/utils/character_valid.c
@@ -0,0 +1,217 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
+ */
+
+#include "utils/character_valid.h"
+
+#include <assert.h>
+
+static const struct xml_char_range base_char_range[] = { {0x41, 0x5a},
+ {0x61, 0x7a}, {0xc0, 0xd6}, {0xd8, 0xf6}, {0x00f8, 0x00ff},
+ {0x100, 0x131}, {0x134, 0x13e}, {0x141, 0x148}, {0x14a, 0x17e},
+ {0x180, 0x1c3}, {0x1cd, 0x1f0}, {0x1f4, 0x1f5}, {0x1fa, 0x217},
+ {0x250, 0x2a8}, {0x2bb, 0x2c1}, {0x386, 0x386}, {0x388, 0x38a},
+ {0x38c, 0x38c}, {0x38e, 0x3a1}, {0x3a3, 0x3ce}, {0x3d0, 0x3d6},
+ {0x3da, 0x3da}, {0x3dc, 0x3dc}, {0x3de, 0x3de}, {0x3e0, 0x3e0},
+ {0x3e2, 0x3f3}, {0x401, 0x40c}, {0x40e, 0x44f}, {0x451, 0x45c},
+ {0x45e, 0x481}, {0x490, 0x4c4}, {0x4c7, 0x4c8}, {0x4cb, 0x4cc},
+ {0x4d0, 0x4eb}, {0x4ee, 0x4f5}, {0x4f8, 0x4f9}, {0x531, 0x556},
+ {0x559, 0x559}, {0x561, 0x586}, {0x5d0, 0x5ea}, {0x5f0, 0x5f2},
+ {0x621, 0x63a}, {0x641, 0x64a}, {0x671, 0x6b7}, {0x6ba, 0x6be},
+ {0x6c0, 0x6ce}, {0x6d0, 0x6d3}, {0x6d5, 0x6d5}, {0x6e5, 0x6e6},
+ {0x905, 0x939}, {0x93d, 0x93d}, {0x958, 0x961}, {0x985, 0x98c},
+ {0x98f, 0x990}, {0x993, 0x9a8}, {0x9aa, 0x9b0}, {0x9b2, 0x9b2},
+ {0x9b6, 0x9b9}, {0x9dc, 0x9dd}, {0x9df, 0x9e1}, {0x9f0, 0x9f1},
+ {0xa05, 0xa0a}, {0xa0f, 0xa10}, {0xa13, 0xa28}, {0xa2a, 0xa30},
+ {0xa32, 0xa33}, {0xa35, 0xa36}, {0xa38, 0xa39}, {0xa59, 0xa5c},
+ {0xa5e, 0xa5e}, {0xa72, 0xa74}, {0xa85, 0xa8b}, {0xa8d, 0xa8d},
+ {0xa8f, 0xa91}, {0xa93, 0xaa8}, {0xaaa, 0xab0}, {0xab2, 0xab3},
+ {0xab5, 0xab9}, {0xabd, 0xabd}, {0xae0, 0xae0}, {0xb05, 0xb0c},
+ {0xb0f, 0xb10}, {0xb13, 0xb28}, {0xb2a, 0xb30}, {0xb32, 0xb33},
+ {0xb36, 0xb39}, {0xb3d, 0xb3d}, {0xb5c, 0xb5d}, {0xb5f, 0xb61},
+ {0xb85, 0xb8a}, {0xb8e, 0xb90}, {0xb92, 0xb95}, {0xb99, 0xb9a},
+ {0xb9c, 0xb9c}, {0xb9e, 0xb9f}, {0xba3, 0xba4}, {0xba8, 0xbaa},
+ {0xbae, 0xbb5}, {0xbb7, 0xbb9}, {0xc05, 0xc0c}, {0xc0e, 0xc10},
+ {0xc12, 0xc28}, {0xc2a, 0xc33}, {0xc35, 0xc39}, {0xc60, 0xc61},
+ {0xc85, 0xc8c}, {0xc8e, 0xc90}, {0xc92, 0xca8}, {0xcaa, 0xcb3},
+ {0xcb5, 0xcb9}, {0xcde, 0xcde}, {0xce0, 0xce1}, {0xd05, 0xd0c},
+ {0xd0e, 0xd10}, {0xd12, 0xd28}, {0xd2a, 0xd39}, {0xd60, 0xd61},
+ {0xe01, 0xe2e}, {0xe30, 0xe30}, {0xe32, 0xe33}, {0xe40, 0xe45},
+ {0xe81, 0xe82}, {0xe84, 0xe84}, {0xe87, 0xe88}, {0xe8a, 0xe8a},
+ {0xe8d, 0xe8d}, {0xe94, 0xe97}, {0xe99, 0xe9f}, {0xea1, 0xea3},
+ {0xea5, 0xea5}, {0xea7, 0xea7}, {0xeaa, 0xeab}, {0xead, 0xeae},
+ {0xeb0, 0xeb0}, {0xeb2, 0xeb3}, {0xebd, 0xebd}, {0xec0, 0xec4},
+ {0xf40, 0xf47}, {0xf49, 0xf69}, {0x10a0, 0x10c5}, {0x10d0, 0x10f6},
+ {0x1100, 0x1100}, {0x1102, 0x1103}, {0x1105, 0x1107}, {0x1109, 0x1109},
+ {0x110b, 0x110c}, {0x110e, 0x1112}, {0x113c, 0x113c}, {0x113e, 0x113e},
+ {0x1140, 0x1140}, {0x114c, 0x114c}, {0x114e, 0x114e}, {0x1150, 0x1150},
+ {0x1154, 0x1155}, {0x1159, 0x1159}, {0x115f, 0x1161}, {0x1163, 0x1163},
+ {0x1165, 0x1165}, {0x1167, 0x1167}, {0x1169, 0x1169}, {0x116d, 0x116e},
+ {0x1172, 0x1173}, {0x1175, 0x1175}, {0x119e, 0x119e}, {0x11a8, 0x11a8},
+ {0x11ab, 0x11ab}, {0x11ae, 0x11af}, {0x11b7, 0x11b8}, {0x11ba, 0x11ba},
+ {0x11bc, 0x11c2}, {0x11eb, 0x11eb}, {0x11f0, 0x11f0}, {0x11f9, 0x11f9},
+ {0x1e00, 0x1e9b}, {0x1ea0, 0x1ef9}, {0x1f00, 0x1f15}, {0x1f18, 0x1f1d},
+ {0x1f20, 0x1f45}, {0x1f48, 0x1f4d}, {0x1f50, 0x1f57}, {0x1f59, 0x1f59},
+ {0x1f5b, 0x1f5b}, {0x1f5d, 0x1f5d}, {0x1f5f, 0x1f7d}, {0x1f80, 0x1fb4},
+ {0x1fb6, 0x1fbc}, {0x1fbe, 0x1fbe}, {0x1fc2, 0x1fc4}, {0x1fc6, 0x1fcc},
+ {0x1fd0, 0x1fd3}, {0x1fd6, 0x1fdb}, {0x1fe0, 0x1fec}, {0x1ff2, 0x1ff4},
+ {0x1ff6, 0x1ffc}, {0x2126, 0x2126}, {0x212a, 0x212b}, {0x212e, 0x212e},
+ {0x2180, 0x2182}, {0x3041, 0x3094}, {0x30a1, 0x30fa}, {0x3105, 0x312c},
+ {0xac00, 0xd7a3}
+};
+
+const struct xml_char_group base_char_group = {
+ sizeof(base_char_range) / sizeof(base_char_range[0]),
+ base_char_range};
+
+static const struct xml_char_range char_range[] = { {0x100, 0xd7ff},
+ {0xe000, 0xfffd}, {0x10000, 0x10ffff}
+};
+
+const struct xml_char_group char_group = {
+ sizeof(char_range) / sizeof(char_range[0]), char_range};
+
+static const struct xml_char_range combining_char_range[] = { {0x300, 0x345},
+ {0x360, 0x361}, {0x483, 0x486}, {0x591, 0x5a1}, {0x5a3, 0x5b9},
+ {0x5bb, 0x5bd}, {0x5bf, 0x5bf}, {0x5c1, 0x5c2}, {0x5c4, 0x5c4},
+ {0x64b, 0x652}, {0x670, 0x670}, {0x6d6, 0x6dc}, {0x6dd, 0x6df},
+ {0x6e0, 0x6e4}, {0x6e7, 0x6e8}, {0x6ea, 0x6ed}, {0x901, 0x903},
+ {0x93c, 0x93c}, {0x93e, 0x94c}, {0x94d, 0x94d}, {0x951, 0x954},
+ {0x962, 0x963}, {0x981, 0x983}, {0x9bc, 0x9bc}, {0x9be, 0x9be},
+ {0x9bf, 0x9bf}, {0x9c0, 0x9c4}, {0x9c7, 0x9c8}, {0x9cb, 0x9cd},
+ {0x9d7, 0x9d7}, {0x9e2, 0x9e3}, {0xa02, 0xa02}, {0xa3c, 0xa3c},
+ {0xa3e, 0xa3e}, {0xa3f, 0xa3f}, {0xa40, 0xa42}, {0xa47, 0xa48},
+ {0xa4b, 0xa4d}, {0xa70, 0xa71}, {0xa81, 0xa83}, {0xabc, 0xabc},
+ {0xabe, 0xac5}, {0xac7, 0xac9}, {0xacb, 0xacd}, {0xb01, 0xb03},
+ {0xb3c, 0xb3c}, {0xb3e, 0xb43}, {0xb47, 0xb48}, {0xb4b, 0xb4d},
+ {0xb56, 0xb57}, {0xb82, 0xb83}, {0xbbe, 0xbc2}, {0xbc6, 0xbc8},
+ {0xbca, 0xbcd}, {0xbd7, 0xbd7}, {0xc01, 0xc03}, {0xc3e, 0xc44},
+ {0xc46, 0xc48}, {0xc4a, 0xc4d}, {0xc55, 0xc56}, {0xc82, 0xc83},
+ {0xcbe, 0xcc4}, {0xcc6, 0xcc8}, {0xcca, 0xccd}, {0xcd5, 0xcd6},
+ {0xd02, 0xd03}, {0xd3e, 0xd43}, {0xd46, 0xd48}, {0xd4a, 0xd4d},
+ {0xd57, 0xd57}, {0xe31, 0xe31}, {0xe34, 0xe3a}, {0xe47, 0xe4e},
+ {0xeb1, 0xeb1}, {0xeb4, 0xeb9}, {0xebb, 0xebc}, {0xec8, 0xecd},
+ {0xf18, 0xf19}, {0xf35, 0xf35}, {0xf37, 0xf37}, {0xf39, 0xf39},
+ {0xf3e, 0xf3e}, {0xf3f, 0xf3f}, {0xf71, 0xf84}, {0xf86, 0xf8b},
+ {0xf90, 0xf95}, {0xf97, 0xf97}, {0xf99, 0xfad}, {0xfb1, 0xfb7},
+ {0xfb9, 0xfb9}, {0x20d0, 0x20dc}, {0x20e1, 0x20e1}, {0x302a, 0x302f},
+ {0x3099, 0x3099}, {0x309a, 0x309a}
+};
+
+const struct xml_char_group combining_char_group = {
+ sizeof(combining_char_range) / sizeof(combining_char_range[0]),
+ combining_char_range };
+
+static const struct xml_char_range digit_char_range[] = { {0x30, 0x39},
+ {0x660, 0x669}, {0x6f0, 0x6f9}, {0x966, 0x96f}, {0x9e6, 0x9ef},
+ {0xa66, 0xa6f}, {0xae6, 0xaef}, {0xb66, 0xb6f}, {0xbe7, 0xbef},
+ {0xc66, 0xc6f}, {0xce6, 0xcef}, {0xd66, 0xd6f}, {0xe50, 0xe59},
+ {0xed0, 0xed9}, {0xf20, 0xf29}
+};
+
+const struct xml_char_group digit_char_group = {
+ sizeof(digit_char_range) / sizeof(digit_char_range[0]),
+ digit_char_range };
+
+static const struct xml_char_range extender_range[] = { {0xb7, 0xb7},
+ {0x2d0, 0x2d0}, {0x2d1, 0x2d1}, {0x387, 0x387}, {0x640, 0x640},
+ {0xe46, 0xe46}, {0xec6, 0xec6}, {0x3005, 0x3005}, {0x3031, 0x3035},
+ {0x309d, 0x309e}, {0x30fc, 0x30fe}
+};
+
+const struct xml_char_group extender_group = {
+ sizeof(extender_range) / sizeof(extender_range[0]),
+ extender_range };
+
+static const struct xml_char_range ideographic_range[] = { {0x3007, 0x3007},
+ {0x3021, 0x3029}, {0x4e00, 0x9fa5}
+};
+
+const struct xml_char_group ideographic_group = {
+ sizeof(ideographic_range) / sizeof(ideographic_range[0]),
+ ideographic_range };
+
+/* The binary search helper function */
+static bool binary_search(unsigned int ch, int left, int right,
+ const struct xml_char_range *range);
+
+/* Search for ch in range[left, right] */
+bool binary_search(unsigned int ch, int left, int right,
+ const struct xml_char_range *range)
+{
+ if (left > right)
+ return false;
+
+ int mid = (left + right) / 2;
+ if (ch >= range[mid].start && ch <= range[mid].end)
+ return true;
+
+ if (ch < range[mid].start)
+ return binary_search(ch, left, mid - 1, range);
+
+ if (ch > range[mid].end)
+ return binary_search(ch, mid + 1, right, range);
+
+ return false;
+}
+
+/**
+ * Test whether certain character belongs to some XML character group
+ *
+ * \param ch The character being tested
+ * \param group The character group
+ * \return true if the character belongs to the group, false otherwise.
+ *
+ * Generally, we use an algorithm like binary search to find the desired
+ * character in the group. The time complexity is about lg(n) and here n is
+ * at most 180, so, I think the algorithm is fast enough for name validation.
+ */
+bool _dom_is_character_in_group(unsigned int ch,
+ const struct xml_char_group *group)
+{
+ int len = group->len;
+ const struct xml_char_range *range = group->range;
+
+ if (ch < range[0].start || ch > range[len-1].end)
+ return false;
+
+ return binary_search(ch, 0, len - 1, range);
+}
+
+#ifdef CHVALID_DEBUG
+/* The following is the testcases for this file.
+ * Compile this file :
+ *
+ * gcc -o test -DCHVALID_DEBUG character_valid.c
+ *
+ */
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+ unsigned int ch = 0x666;
+
+ assert(is_digit(ch) == true);
+ assert(is_base_char(ch) == false);
+ assert(is_char(ch) == true);
+ assert(is_extender(ch) == false);
+ assert(is_combining_char(ch) == false);
+ assert(is_ideographic(ch) == false);
+
+ ch = 0xf40;
+
+ assert(is_digit(ch) == false);
+ assert(is_base_char(ch) == true);
+ assert(is_char(ch) == true);
+ assert(is_extender(ch) == false);
+ assert(is_combining_char(ch) == false);
+ assert(is_ideographic(ch) == false);
+
+ printf("The test pass.\n");
+ return 0;
+}
+
+#endif
diff --git a/src/utils/character_valid.h b/src/utils/character_valid.h
new file mode 100644
index 0000000..5094e7c
--- /dev/null
+++ b/src/utils/character_valid.h
@@ -0,0 +1,54 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
+ *
+ * This file contains the API used to validate whether certain character in
+ * name/value is legal according the XML 1.0 standard. See
+ *
+ * http://www.w3.org/TR/2004/REC-xml-20040204/
+ * http://www.w3.org/TR/REC-xml/
+ *
+ * for detail.
+ */
+
+#ifndef dom_utils_character_valid_h_
+#define dom_utils_character_valid_h_
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+struct xml_char_range {
+ unsigned int start;
+ unsigned int end;
+};
+
+struct xml_char_group {
+ size_t len;
+ const struct xml_char_range *range;
+};
+
+/* The groups */
+extern const struct xml_char_group base_char_group;
+extern const struct xml_char_group char_group;
+extern const struct xml_char_group combining_char_group;
+extern const struct xml_char_group digit_char_group;
+extern const struct xml_char_group extender_group;
+extern const struct xml_char_group ideographic_group;
+
+bool _dom_is_character_in_group(unsigned int ch,
+ const struct xml_char_group *group);
+
+#define is_base_char(ch) _dom_is_character_in_group((ch), &base_char_group)
+#define is_char(ch) _dom_is_character_in_group((ch), &char_group)
+#define is_combining_char(ch) _dom_is_character_in_group((ch), \
+ &combining_char_group)
+#define is_digit(ch) _dom_is_character_in_group((ch), &digit_char_group)
+#define is_extender(ch) _dom_is_character_in_group((ch), &extender_group)
+#define is_ideographic(ch) _dom_is_character_in_group((ch), &ideographic_group)
+
+#define is_letter(ch) (is_base_char(ch) || is_ideographic(ch))
+
+#endif
+
diff --git a/src/utils/hashtable.c b/src/utils/hashtable.c
new file mode 100644
index 0000000..c2ff8ce
--- /dev/null
+++ b/src/utils/hashtable.c
@@ -0,0 +1,492 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2006 Rob Kendrick <rjek@rjek.com>
+ * Copyright 2006 Richard Wilson <info@tinct.net>
+ * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <assert.h>
+#ifdef TEST_RIG
+#include <stdio.h>
+#endif
+#include "utils/hashtable.h"
+
+/* The hash table entry */
+struct _dom_hash_entry {
+ void *key; /**< The key pointer */
+ void *value; /**< The value pointer */
+ struct _dom_hash_entry *next; /**< Next entry */
+};
+
+/* The hash table */
+struct dom_hash_table {
+ unsigned int nchains; /**< The chains number */
+ dom_hash_func hash; /**< The hash function */
+ struct _dom_hash_entry **chain; /**< The chain head */
+ unsigned int number; /**< The enries in this table */
+
+ dom_alloc alloc; /**< Memory allocation function */
+ void *ptr; /**< The private data for the memory allocator */
+};
+
+
+/**
+ * Create a new hash table, and return a context for it. The memory consumption
+ * of a hash table is approximately 8 + (nchains * 12) bytes if it is empty.
+ *
+ * \param chains Number of chains/buckets this hash table will have. This
+ * should be a prime number, and ideally a prime number just
+ * over a power of two, for best performance and distribution
+ * \param hash The hash function
+ * \param alloc The memory allocator
+ * \param ptr The private pointer for the allocator
+ * \return struct dom_hash_table containing the context of this hash table or
+ * NULL if there is insufficent memory to create it and its chains.
+ */
+struct dom_hash_table *_dom_hash_create(unsigned int chains, dom_hash_func hash,
+ dom_alloc alloc, void *ptr)
+{
+ struct dom_hash_table *r = alloc(NULL, sizeof(struct dom_hash_table),
+ ptr);
+
+ if (r == NULL) {
+ return NULL;
+ }
+
+ r->nchains = chains;
+ r->hash = hash;
+ r->alloc = alloc;
+ r->ptr = ptr;
+ r->chain = (struct _dom_hash_entry **)alloc(NULL,
+ chains*sizeof(struct _dom_hash_entry *), ptr);
+ r->number = 0;
+
+ unsigned int i;
+ for (i = 0; i < chains; i++)
+ r->chain[i] = NULL;
+
+ if (r->chain == NULL) {
+ alloc(r, 0, ptr);
+ return NULL;
+ }
+
+ return r;
+}
+
+/**
+ * Clone a hash table.
+ *
+ * \param ht Hash table to clone.
+ * \param alloc The allocator.
+ * \param pw The private data for the allocator.
+ * \param kf The function pointer used to copy the key.
+ * \param key_pw The private data for the key cloner.
+ * \param vf The function pointer used to copy the value.
+ * \param value_pw The private data for the value cloner.
+ *
+ * \return The cloned hash table.
+ */
+struct dom_hash_table *_dom_hash_clone(struct dom_hash_table *ht,
+ dom_alloc alloc, void *pw, dom_key_func kf, void *key_pw,
+ dom_value_func vf, void *value_pw)
+{
+ struct dom_hash_table *ret;
+
+ ret = _dom_hash_create(ht->nchains, ht->hash, alloc, pw);
+ if (ret == NULL)
+ return NULL;
+
+ void *key = NULL, *nkey = NULL;
+ void *value = NULL, *nvalue = NULL;
+ unsigned int c1, *c2 = NULL;
+ while ( (key = _dom_hash_iterate(ht, &c1, &c2)) != NULL) {
+ nkey = kf(key, key_pw, alloc, pw, true);
+ if (nkey == NULL) {
+ _dom_hash_destroy(ret, kf, key_pw, vf, value_pw);
+ return NULL;
+ }
+
+ value = _dom_hash_get(ht, key);
+ nvalue = vf(value, value_pw, alloc, pw, true);
+ if (nvalue == NULL) {
+ kf(nkey, key_pw, alloc, pw, false);
+ _dom_hash_destroy(ret, kf, key_pw, vf, value_pw);
+ return NULL;
+ }
+
+ if (_dom_hash_add(ret, nkey, nvalue, false) == false) {
+ _dom_hash_destroy(ret, kf, key_pw, vf, value_pw);
+ return NULL;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * Destroys a hash table, freeing all memory associated with it.
+ *
+ * \param ht Hash table to destroy. After the function returns, this
+ * will nolonger be valid
+ * \param kf The key destroy function
+ * \param key_pw The key destroy function private data
+ * \param vf The value destroy function
+ * \param value_pw The value destroy function private data
+ */
+void _dom_hash_destroy(struct dom_hash_table *ht, dom_key_func kf,
+ void *key_pw, dom_value_func vf, void *value_pw)
+{
+ unsigned int i;
+
+ if (ht == NULL)
+ return;
+
+ assert(ht->alloc != NULL);
+
+ for (i = 0; i < ht->nchains; i++) {
+ if (ht->chain[i] != NULL) {
+ struct _dom_hash_entry *e = ht->chain[i];
+ while (e) {
+ struct _dom_hash_entry *n = e->next;
+ if (kf != NULL) {
+ kf(e->key, key_pw, ht->alloc,
+ ht->ptr, false);
+ }
+ if (vf != NULL) {
+ vf(e->value, value_pw, ht->alloc,
+ ht->ptr, false);
+ }
+ ht->alloc(e, 0, ht->ptr);
+ e = n;
+ }
+ }
+ }
+
+ ht->alloc(ht->chain, 0, ht->ptr);
+ ht->alloc(ht, 0, ht->ptr);
+}
+
+/**
+ * Adds a key/value pair to a hash table
+ *
+ * \param ht The hash table context to add the key/value pair to.
+ * \param key The key to associate the value with.
+ * \param value The value to associate the key with.
+ * \return true if the add succeeded, false otherwise. (Failure most likely
+ * indicates insufficent memory to make copies of the key and value.
+ */
+bool _dom_hash_add(struct dom_hash_table *ht, void *key, void *value,
+ bool replace)
+{
+ unsigned int h, c;
+ struct _dom_hash_entry *e;
+
+ if (ht == NULL || key == NULL || value == NULL)
+ return false;
+
+ h = ht->hash(key);
+ c = h % ht->nchains;
+
+ for (e = ht->chain[c]; e; e = e->next)
+ if (key == e->key) {
+ if (replace == true) {
+ e->value = value;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ assert(ht->alloc != NULL);
+
+ e = ht->alloc(NULL, sizeof(struct _dom_hash_entry), ht->ptr);
+ if (e == NULL) {
+ return false;
+ }
+
+ e->key = key;
+ e->value = value;
+
+ e->next = ht->chain[c];
+ ht->chain[c] = e;
+ ht->number ++;
+
+ return true;
+}
+
+/**
+ * Looks up a the value associated with with a key from a specific hash table.
+ *
+ * \param ht The hash table context to look up
+ * \param key The key to search for
+ * \return The value associated with the key, or NULL if it was not found.
+ */
+void *_dom_hash_get(struct dom_hash_table *ht, void *key)
+{
+ unsigned int h, c;
+ struct _dom_hash_entry *e;
+
+ if (ht == NULL || key == NULL)
+ return NULL;
+
+ h = ht->hash(key);
+ c = h % ht->nchains;
+
+ for (e = ht->chain[c]; e; e = e->next)
+ if (key == e->key)
+ return e->value;
+
+ return NULL;
+}
+
+/**
+ * Delete the key from the hashtable.
+ *
+ * \param ht The hashtable object
+ * \param key The key to delete
+ * \return The deleted value
+ */
+void *_dom_hash_del(struct dom_hash_table *ht, void *key)
+{
+ unsigned int h, c;
+ struct _dom_hash_entry *e, *p;
+ void *ret;
+
+ if (ht == NULL || key == NULL)
+ return NULL;
+
+ h = ht->hash(key);
+ c = h % ht->nchains;
+
+ assert(ht->alloc != NULL);
+
+ p = ht->chain[c];
+ for (e = p; e; p = e, e = e->next)
+ if (key == e->key) {
+ if (p != e) {
+ p->next = e->next;
+ } else {
+ /* The first item in this chain is target*/
+ ht->chain[c] = e->next;
+ }
+
+ ret = e->value;
+ ht->alloc(e, 0, ht->ptr);
+ ht->number --;
+ return ret;
+ }
+
+ return NULL;
+}
+
+/**
+ * Iterate through all available hash keys.
+ *
+ * \param ht The hash table context to iterate.
+ * \param c1 Pointer to first context
+ * \param c2 Pointer to second context (set to 0 on first call)
+ * \return The next hash key, or NULL for no more keys
+ */
+void *_dom_hash_iterate(struct dom_hash_table *ht, unsigned int *c1,
+ unsigned int **c2)
+{
+ struct _dom_hash_entry **he = (struct _dom_hash_entry **)c2;
+
+ if (ht == NULL)
+ return NULL;
+
+ if (!*he)
+ *c1 = -1;
+ else
+ *he = (*he)->next;
+
+ if (*he)
+ return (*he)->key;
+
+ while (!*he) {
+ (*c1)++;
+ if (*c1 >= ht->nchains)
+ return NULL;
+ *he = ht->chain[*c1];
+ }
+ return (*he)->key;
+}
+
+/**
+ * Get the number of elements in this hash table
+ *
+ * \param ht The hash table
+ *
+ * \return the number of elements
+ */
+unsigned int _dom_hash_get_length(struct dom_hash_table *ht)
+{
+ return ht->number;
+}
+
+/**
+ * Get the chain number of this hash table
+ *
+ * \param ht The hash table
+ *
+ * \return the number of chains
+ */
+unsigned int _dom_hash_get_chains(struct dom_hash_table *ht)
+{
+ return ht->nchains;
+}
+
+/**
+ * Get the hash function of this hash table
+ *
+ * \param ht The hash table
+ *
+ * \return the hash function
+ */
+dom_hash_func _dom_hash_get_func(struct dom_hash_table *ht)
+{
+ return ht->hash;
+}
+
+/* A simple test rig. To compile, use:
+ * gcc -g -o hashtest -I../ -I../../include -DTEST_RIG hashtable.c
+ *
+ * If you make changes to this hash table implementation, please rerun this
+ * test, and if possible, through valgrind to make sure there are no memory
+ * leaks or invalid memory accesses. If you add new functionality, please
+ * include a test for it that has good coverage along side the other tests.
+ */
+
+#ifdef TEST_RIG
+
+
+/**
+ * Hash a pointer, returning a 32bit value.
+ *
+ * \param ptr The pointer to hash.
+ * \return the calculated hash value for the pointer.
+ */
+
+static inline unsigned int _dom_hash_pointer_fnv(void *ptr)
+{
+ return (unsigned int) ptr;
+}
+
+static void *test_alloc(void *p, size_t size, void *ptr)
+{
+ if (p != NULL) {
+ free(p);
+ return NULL;
+ }
+
+ if (p == NULL) {
+ return malloc(size);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ struct dom_hash_table *a, *b;
+ FILE *dict;
+ char keybuf[BUFSIZ], valbuf[BUFSIZ];
+ int i;
+ char *cow="cow", *moo="moo", *pig="pig", *oink="oink",
+ *chicken="chikcken", *cluck="cluck",
+ *dog="dog", *woof="woof", *cat="cat",
+ *meow="meow";
+ void *ret;
+
+ a = _dom_hash_create(79, _dom_hash_pointer_fnv, test_alloc, NULL);
+ assert(a != NULL);
+
+ b = _dom_hash_create(103, _dom_hash_pointer_fnv, test_alloc, NULL);
+ assert(b != NULL);
+
+ _dom_hash_add(a, cow, moo ,true);
+ _dom_hash_add(b, moo, cow ,true);
+
+ _dom_hash_add(a, pig, oink ,true);
+ _dom_hash_add(b, oink, pig ,true);
+
+ _dom_hash_add(a, chicken, cluck ,true);
+ _dom_hash_add(b, cluck, chicken ,true);
+
+ _dom_hash_add(a, dog, woof ,true);
+ _dom_hash_add(b, woof, dog ,true);
+
+ _dom_hash_add(a, cat, meow ,true);
+ _dom_hash_add(b, meow, cat ,true);
+
+#define MATCH(x,y) assert(!strcmp((char *)hash_get(a, x), (char *)y)); \
+ assert(!strcmp((char *)hash_get(b, y), (char *)x))
+ MATCH(cow, moo);
+ MATCH(pig, oink);
+ MATCH(chicken, cluck);
+ MATCH(dog, woof);
+ MATCH(cat, meow);
+
+ assert(hash_get_length(a) == 5);
+ assert(hash_get_length(b) == 5);
+
+ _dom_hash_del(a, cat);
+ _dom_hash_del(b, meow);
+ assert(hash_get(a, cat) == NULL);
+ assert(hash_get(b, meow) == NULL);
+
+ assert(hash_get_length(a) == 4);
+ assert(hash_get_length(b) == 4);
+
+ _dom_hash_destroy(a, NULL, NULL);
+ _dom_hash_destroy(b, NULL, NULL);
+
+ /* This test requires /usr/share/dict/words - a large list of English
+ * words. We load the entire file - odd lines are used as keys, and
+ * even lines are used as the values for the previous line. we then
+ * work through it again making sure everything matches.
+ *
+ * We do this twice - once in a hash table with many chains, and once
+ * with a hash table with fewer chains.
+ */
+
+ a = _dom_hash_create(1031, _dom_hash_pointer_fnv, test_alloc, NULL);
+ b = _dom_hash_create(7919, _dom_hash_pointer_fnv, test_alloc, NULL);
+
+ dict = fopen("/usr/share/dict/words", "r");
+ if (dict == NULL) {
+ fprintf(stderr, "Unable to open /usr/share/dict/words - \
+ extensive testing skipped.\n");
+ exit(0);
+ }
+
+ while (!feof(dict)) {
+ fscanf(dict, "%s", keybuf);
+ fscanf(dict, "%s", valbuf);
+ _dom_hash_add(a, keybuf, valbuf, true);
+ _dom_hash_add(b, keybuf, valbuf, true);
+ }
+
+ for (i = 0; i < 5; i++) {
+ fseek(dict, 0, SEEK_SET);
+
+ while (!feof(dict)) {
+ fscanf(dict, "%s", keybuf);
+ fscanf(dict, "%s", valbuf);
+ assert(strcmp(hash_get(a, keybuf), valbuf) == 0);
+ assert(strcmp(hash_get(b, keybuf), valbuf) == 0);
+ }
+ }
+
+ _dom_hash_destroy(a, NULL, NULL);
+ _dom_hash_destroy(b, NULL, NULL);
+
+ fclose(dict);
+
+ return 0;
+}
+
+#endif
diff --git a/src/utils/hashtable.h b/src/utils/hashtable.h
new file mode 100644
index 0000000..3cfe95d
--- /dev/null
+++ b/src/utils/hashtable.h
@@ -0,0 +1,42 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2006 Rob Kendrick <rjek@rjek.com>
+ * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
+ */
+
+#ifndef dom_utils_hashtable_h_
+#define dom_utils_hashtable_h_
+
+#include <stdbool.h>
+#include <dom/functypes.h>
+
+typedef struct dom_hash_table dom_hash_table;
+/* The hash function */
+typedef unsigned int (*dom_hash_func)(void *key);
+/* Function to clone/delete key */
+typedef void *(*dom_key_func)(void *key, void *pw, dom_alloc alloc,
+ void *alloc_pw, bool clone);
+/* Function to clone/delete value */
+typedef void *(*dom_value_func)(void *value, void *pw, dom_alloc alloc,
+ void *alloc_pw, bool clone);
+
+struct dom_hash_table *_dom_hash_create(unsigned int chains, dom_hash_func hash,
+ dom_alloc alloc, void *ptr);
+struct dom_hash_table *_dom_hash_clone(struct dom_hash_table *ht,
+ dom_alloc alloc, void *pw, dom_key_func kf, void *key_pw,
+ dom_value_func vf, void *value_pw);
+void _dom_hash_destroy(struct dom_hash_table *ht, dom_key_func kf, void *key_pw,
+ dom_value_func vf, void *value_pw);
+bool _dom_hash_add(struct dom_hash_table *ht, void *key, void *value,
+ bool replace);
+void *_dom_hash_get(struct dom_hash_table *ht, void *key);
+void *_dom_hash_del(struct dom_hash_table *ht, void *key);
+void *_dom_hash_iterate(struct dom_hash_table *ht, unsigned int *c1,
+ unsigned int **c2);
+unsigned int _dom_hash_get_length(struct dom_hash_table *ht);
+unsigned int _dom_hash_get_chains(struct dom_hash_table *ht);
+dom_hash_func _dom_hash_get_func(struct dom_hash_table *ht);
+
+#endif
diff --git a/src/utils/list.h b/src/utils/list.h
new file mode 100644
index 0000000..6e3ba20
--- /dev/null
+++ b/src/utils/list.h
@@ -0,0 +1,61 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
+ *
+ * This file contains the list structure used to compose lists.
+ *
+ * Note: This is a implementation of a doubld-linked cyclar list.
+ */
+
+#ifndef dom_utils_list_h_
+#define dom_utils_list_h_
+
+#include <stddef.h>
+
+struct list_entry {
+ struct list_entry *prev;
+ struct list_entry *next;
+};
+
+/**
+ * Initialise a list_entry structure
+ *
+ * \param ent The entry to initialise
+ */
+static inline void list_init(struct list_entry *ent)
+{
+ ent->prev = ent;
+ ent->next = ent;
+}
+
+/**
+ * Append a new list_entry after the list
+ *
+ * \param head The list header
+ * \param new The new entry
+ */
+static inline void list_append(struct list_entry *head, struct list_entry *new)
+{
+ new->next = head;
+ new->prev = head->prev;
+ head->prev->next = new;
+ head->prev = new;
+}
+
+/**
+ * Delete a list_entry from the list
+ *
+ * \param entry The entry need to be deleted from the list
+ */
+static inline void list_del(struct list_entry *ent)
+{
+ ent->prev->next = ent->next;
+ ent->next->prev = ent->prev;
+
+ ent->prev = ent;
+ ent->next = ent;
+}
+
+#endif
diff --git a/src/utils/namespace.c b/src/utils/namespace.c
index ca5b01d..8d109ae 100644
--- a/src/utils/namespace.c
+++ b/src/utils/namespace.c
@@ -1,8 +1,9 @@
/*
* This file is part of libdom.
* Licensed under the MIT License,
- * http://www.opensource.org/licenses/mit-license.php
+ * http://www.opensource.org/licenses/mit-license.php
* Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
*/
#include <string.h>
@@ -10,6 +11,7 @@
#include <dom/dom.h>
#include "utils/namespace.h"
+#include "utils/validate.h"
#include "utils/utils.h"
@@ -18,7 +20,7 @@ static struct dom_string *xml;
/** XMLNS prefix */
static struct dom_string *xmlns;
-/** The namespace strings */
+/* The namespace strings */
static const char *namespaces[DOM_NAMESPACE_COUNT] = {
NULL,
"http://www.w3.org/1999/xhtml",
@@ -37,7 +39,7 @@ struct dom_string *dom_namespaces[DOM_NAMESPACE_COUNT] = {
* Initialise the namespace component
*
* \param alloc Pointer to memory (de)allocation function
- * \param pw Pointer to client-specific private data
+ * \param pw Pointer to client-specific private data
* \return DOM_NO_ERR on success.
*/
dom_exception _dom_namespace_initialise(dom_alloc alloc, void *pw)
@@ -130,10 +132,19 @@ dom_exception _dom_namespace_finalise(void)
dom_exception _dom_namespace_validate_qname(struct dom_string *qname,
struct dom_string *namespace)
{
- uint32_t colon;
+ uint32_t colon, len;
+
+ if (qname == NULL){
+ if (namespace != NULL)
+ return DOM_NAMESPACE_ERR;
+ if (namespace == NULL)
+ return DOM_NO_ERR;
+ }
+
+ if (_dom_validate_name(qname) == false)
+ return DOM_NAMESPACE_ERR;
- /** \todo search qname for invalid characters */
- /** \todo ensure qname is not malformed */
+ len = dom_string_length(qname);
/* Find colon */
colon = dom_string_index(qname, ':');
@@ -147,9 +158,14 @@ dom_exception _dom_namespace_validate_qname(struct dom_string *qname,
dom_string_cmp(qname, xmlns) != 0) {
return DOM_NAMESPACE_ERR;
}
+ } else if (colon == 0) {
+ /* Some name like ":name" */
+ if (namespace != NULL)
+ return DOM_NAMESPACE_ERR;
} else {
/* Prefix */
struct dom_string *prefix;
+ struct dom_string *lname;
dom_exception err;
/* Ensure there is a namespace URI */
@@ -157,11 +173,21 @@ dom_exception _dom_namespace_validate_qname(struct dom_string *qname,
return DOM_NAMESPACE_ERR;
}
- err = dom_string_substr(qname, 0, colon - 1, &prefix);
+ err = dom_string_substr(qname, 0, colon, &prefix);
if (err != DOM_NO_ERR) {
return err;
}
+ err = dom_string_substr(qname, colon + 1, len, &lname);
+ if (err != DOM_NO_ERR) {
+ return err;
+ }
+
+ if (_dom_validate_ncname(prefix) == false ||
+ _dom_validate_ncname(lname) == false) {
+ return DOM_NAMESPACE_ERR;
+ }
+
/* Test for invalid XML namespace */
if (dom_string_cmp(prefix, xml) == 0 &&
dom_string_cmp(namespace,
@@ -223,7 +249,7 @@ dom_exception _dom_namespace_split_qname(struct dom_string *qname,
}
} else {
/* Found one => prefix */
- err = dom_string_substr(qname, 0, colon - 1, prefix);
+ err = dom_string_substr(qname, 0, colon, prefix);
if (err != DOM_NO_ERR) {
return err;
}
@@ -240,3 +266,32 @@ dom_exception _dom_namespace_split_qname(struct dom_string *qname,
return DOM_NO_ERR;
}
+/**
+ * Get the XML prefix dom_string
+ *
+ * \return the xml prefix dom_string.
+ *
+ * Note: The client of this function may or may not call the dom_string_ref
+ * on the returned dom_string, because this string will only be destroyed when
+ * the dom_finalise is called. But if the client call dom_string_ref, it must
+ * call dom_string_unref to maintain a correct ref count of the dom_string.
+ */
+dom_string *_dom_namespace_get_xml_prefix(void)
+{
+ return xml;
+}
+
+/**
+ * Get the XMLNS prefix dom_string.
+ *
+ * \return the xmlns prefix dom_string
+ *
+ * Note: The client of this function may or may not call the dom_string_ref
+ * on the returned dom_string, because this string will only be destroyed when
+ * the dom_finalise is called. But if the client call dom_string_ref, it must
+ * call dom_string_unref to maintain a correct ref count of the dom_string.
+ */
+dom_string *_dom_namespace_get_xmlns_prefix(void)
+{
+ return xmlns;
+}
diff --git a/src/utils/namespace.h b/src/utils/namespace.h
index ec69035..900c9ee 100644
--- a/src/utils/namespace.h
+++ b/src/utils/namespace.h
@@ -14,6 +14,7 @@
struct dom_document;
struct dom_string;
+
/* Initialise the namespace component */
dom_exception _dom_namespace_initialise(dom_alloc alloc, void *pw);
@@ -28,5 +29,11 @@ dom_exception _dom_namespace_validate_qname(struct dom_string *qname,
dom_exception _dom_namespace_split_qname(struct dom_string *qname,
struct dom_string **prefix, struct dom_string **localname);
+/* Get the XML prefix dom_string */
+struct dom_string *_dom_namespace_get_xml_prefix(void);
+
+/* Get the XMLNS prefix dom_string */
+struct dom_string *_dom_namespace_get_xmlns_prefix(void);
+
#endif
diff --git a/src/utils/resource_mgr.c b/src/utils/resource_mgr.c
new file mode 100644
index 0000000..c9c86d3
--- /dev/null
+++ b/src/utils/resource_mgr.c
@@ -0,0 +1,105 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
+ */
+
+#include "resource_mgr.h"
+
+#include <string.h>
+#include <assert.h>
+
+#include <libwapcaplet/libwapcaplet.h>
+#include "core/string.h"
+
+/**
+ * Allocate some memory with this allocator
+ *
+ * \param res The resource manager
+ * \param size The size of memory to allocate
+ * \return the allocated memory pointer.
+ */
+void *_dom_resource_mgr_alloc(struct dom_resource_mgr *res, void *ptr,
+ size_t size)
+{
+ return res->alloc(ptr, size, res->pw);
+}
+
+/**
+ * Create a dom_string using this resource manager
+ *
+ * \param res The resource manager
+ * \param data The data pointer
+ * \param len The length of data
+ * \param result The returned dom_string
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ */
+dom_exception _dom_resource_mgr_create_string(struct dom_resource_mgr *res,
+ const uint8_t *data, size_t len, struct dom_string **result)
+{
+ return dom_string_create(res->alloc, res->pw, data, len, result);
+}
+
+/**
+ * Create a lwc_string using this resource manager
+ *
+ * \param res The resource manager
+ * \param data The data pointer
+ * \param len The length of the data
+ * \param result The returned lwc_string
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ */
+dom_exception _dom_resource_mgr_create_lwcstring(struct dom_resource_mgr *res,
+ const uint8_t *data, size_t len, struct lwc_string_s **result)
+{
+ lwc_error lerr;
+
+ assert(res->ctx != NULL);
+
+ lerr = lwc_context_intern(res->ctx, (const char *) data, len,
+ result);
+
+ return _dom_exception_from_lwc_error(lerr);
+}
+
+/**
+ * Create a dom_string from a lwc_string using this resource manager
+ *
+ * \param res The resource manager
+ * \param str The dom_string to intern
+ * \param result The returned lwc_string
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ */
+dom_exception _dom_resource_mgr_create_string_from_lwcstring(
+ struct dom_resource_mgr *res, struct lwc_string_s *str,
+ struct dom_string **result)
+{
+ assert(res->ctx != NULL);
+
+ return _dom_string_create_from_lwcstring(res->alloc, res->pw, res->ctx,
+ str, result);
+}
+
+/**
+ * Create a hash table using this resource manager
+ *
+ * \param res The resource manager
+ * \param chains The number of buckets of the hash table
+ * \param f The hash function
+ * \param ht The returned hash table
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ */
+dom_exception _dom_resource_mgr_create_hashtable(struct dom_resource_mgr *res,
+ size_t chains, dom_hash_func f, struct dom_hash_table **ht)
+{
+ struct dom_hash_table *ret;
+
+ ret = _dom_hash_create(chains, f, res->alloc, res->pw);
+ if (ret == NULL)
+ return DOM_NO_MEM_ERR;
+
+ *ht = ret;
+ return DOM_NO_ERR;
+}
+
diff --git a/src/utils/resource_mgr.h b/src/utils/resource_mgr.h
new file mode 100644
index 0000000..b58f665
--- /dev/null
+++ b/src/utils/resource_mgr.h
@@ -0,0 +1,45 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
+ */
+
+#ifndef dom_utils_resource_mgr_h_
+#define dom_utils_resource_mgr_h_
+
+#include <dom/functypes.h>
+#include <dom/core/exceptions.h>
+
+#include "hashtable.h"
+
+struct lwc_context_s;
+struct lwc_string_s;
+struct dom_string;
+
+/**
+ * Resource manager
+ */
+typedef struct dom_resource_mgr {
+ dom_alloc alloc;
+ void *pw;
+ struct lwc_context_s *ctx;
+} dom_resource_mgr;
+
+void *_dom_resource_mgr_alloc(struct dom_resource_mgr *res, void *ptr,
+ size_t size);
+
+dom_exception _dom_resource_mgr_create_string(struct dom_resource_mgr *res,
+ const uint8_t *data, size_t len, struct dom_string **result);
+
+dom_exception _dom_resource_mgr_create_lwcstring(struct dom_resource_mgr *res,
+ const uint8_t *data, size_t len, struct lwc_string_s **result);
+
+dom_exception _dom_resource_mgr_create_string_from_lwcstring(
+ struct dom_resource_mgr *res, struct lwc_string_s *str,
+ struct dom_string **result);
+
+dom_exception _dom_resource_mgr_create_hashtable(struct dom_resource_mgr *res,
+ size_t chains, dom_hash_func f, struct dom_hash_table **ht);
+
+#endif
diff --git a/src/utils/validate.c b/src/utils/validate.c
new file mode 100644
index 0000000..eb6cb22
--- /dev/null
+++ b/src/utils/validate.c
@@ -0,0 +1,177 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
+ */
+
+#include <inttypes.h>
+#include <stddef.h>
+
+#include "utils/validate.h"
+
+#include <dom/core/string.h>
+
+#include "utils/character_valid.h"
+#include "utils/namespace.h"
+#include "utils/utils.h"
+
+/* An combination of various tests */
+static bool is_first_char(uint32_t ch);
+static bool is_name_char(uint32_t ch);
+
+/* Test whether the character can be the first character of
+ * a NCName. */
+static bool is_first_char(uint32_t ch)
+{
+ /* Refer http://www.w3.org/TR/REC-xml/ for detail */
+ if (((ch >= 'a') && (ch <= 'z')) ||
+ ((ch >= 'A') && (ch <= 'Z')) ||
+ (ch == '_') || (ch == ':') ||
+ ((ch >= 0xC0) && (ch <= 0xD6)) ||
+ ((ch >= 0xD8) && (ch <= 0xF6)) ||
+ ((ch >= 0xF8) && (ch <= 0x2FF)) ||
+ ((ch >= 0x370) && (ch <= 0x37D)) ||
+ ((ch >= 0x37F) && (ch <= 0x1FFF)) ||
+ ((ch >= 0x200C) && (ch <= 0x200D)) ||
+ ((ch >= 0x2070) && (ch <= 0x218F)) ||
+ ((ch >= 0x2C00) && (ch <= 0x2FEF)) ||
+ ((ch >= 0x3001) && (ch <= 0xD7FF)) ||
+ ((ch >= 0xF900) && (ch <= 0xFDCF)) ||
+ ((ch >= 0xFDF0) && (ch <= 0xFFFD)) ||
+ ((ch >= 0x10000) && (ch <= 0xEFFFF)))
+ return true;
+
+ if (is_letter(ch) || ch == (uint32_t) '_' || ch == (uint32_t) ':') {
+ return true;
+ }
+
+ return false;
+}
+
+/* Test whether the character can be a part of a NCName */
+static bool is_name_char(uint32_t ch)
+{
+ /* Refer http://www.w3.org/TR/REC-xml/ for detail */
+ if (((ch >= 'a') && (ch <= 'z')) ||
+ ((ch >= 'A') && (ch <= 'Z')) ||
+ ((ch >= '0') && (ch <= '9')) || /* !start */
+ (ch == '_') || (ch == ':') ||
+ (ch == '-') || (ch == '.') || (ch == 0xB7) || /* !start */
+ ((ch >= 0xC0) && (ch <= 0xD6)) ||
+ ((ch >= 0xD8) && (ch <= 0xF6)) ||
+ ((ch >= 0xF8) && (ch <= 0x2FF)) ||
+ ((ch >= 0x300) && (ch <= 0x36F)) || /* !start */
+ ((ch >= 0x370) && (ch <= 0x37D)) ||
+ ((ch >= 0x37F) && (ch <= 0x1FFF)) ||
+ ((ch >= 0x200C) && (ch <= 0x200D)) ||
+ ((ch >= 0x203F) && (ch <= 0x2040)) || /* !start */
+ ((ch >= 0x2070) && (ch <= 0x218F)) ||
+ ((ch >= 0x2C00) && (ch <= 0x2FEF)) ||
+ ((ch >= 0x3001) && (ch <= 0xD7FF)) ||
+ ((ch >= 0xF900) && (ch <= 0xFDCF)) ||
+ ((ch >= 0xFDF0) && (ch <= 0xFFFD)) ||
+ ((ch >= 0x10000) && (ch <= 0xEFFFF)))
+ return true;
+
+ if (is_letter(ch) == true)
+ return true;
+ if (is_digit(ch) == true)
+ return true;
+ if (is_combining_char(ch) == true)
+ return true;
+ if (is_extender(ch) == true)
+ return true;
+
+ if (ch == (uint32_t) '.' || ch == (uint32_t) '-' ||
+ ch == (uint32_t) '_' || ch == (uint32_t) ':')
+ return true;
+
+ return false;
+}
+
+/**
+ * Test whether the name is a valid one according XML 1.0 standard.
+ * For the standard please refer:
+ *
+ * http://www.w3.org/TR/2004/REC-xml-20040204/
+ *
+ * \param name The name need to be tested
+ * \return true if ::name is valid, false otherwise.
+ */
+bool _dom_validate_name(struct dom_string *name)
+{
+ uint32_t ch, len, i;
+ dom_exception err;
+
+ if (name == NULL)
+ return false;
+
+ len = dom_string_length(name);
+ if (len == 0)
+ return false;
+
+ /* Test the first character of this string */
+ err = dom_string_at(name, 0, &ch);
+ if (err != DOM_NO_ERR)
+ return false;
+
+ if (is_first_char(ch) == false)
+ return false;
+
+ /* Test all remain characters in this string */
+ for(i = 1; i < len; i++) {
+ err = dom_string_at(name, i, &ch);
+ if (err != DOM_NO_ERR)
+ return false;
+
+ if (is_name_char(ch) != true)
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Validate whether the string is a legal NCName.
+ * Refer http://www.w3.org/TR/REC-xml-names/ for detail.
+ *
+ * \param str The name to validate
+ * \return true if ::name is valid, false otherwise.
+ */
+bool _dom_validate_ncname(struct dom_string *name)
+{
+ uint32_t ch, len, i;
+ dom_exception err;
+
+ if (name == NULL)
+ return false;
+
+ len = dom_string_length(name);
+ if (len == 0)
+ return false;
+
+ /* Test the first character of this string */
+ err = dom_string_at(name, 0, &ch);
+ if (err != DOM_NO_ERR)
+ return false;
+
+ if (is_letter(ch) == false && ch != (uint32_t) '_')
+ return false;
+
+ /* Test all remain characters in this string */
+ for(i = 1; i < len; i++) {
+ err = dom_string_at(name, i, &ch);
+ if (err != DOM_NO_ERR)
+ return false;
+
+ if (is_name_char(ch) == false)
+ return false;
+
+ if (ch == (uint32_t) ':')
+ return false;
+ }
+
+ return true;
+}
+
diff --git a/src/utils/validate.h b/src/utils/validate.h
new file mode 100644
index 0000000..5d375e7
--- /dev/null
+++ b/src/utils/validate.h
@@ -0,0 +1,26 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
+ *
+ * This file contains the API used to validate whether certain element's
+ * name/namespace are legal according the XML 1.0 standard. See
+ *
+ * http://www.w3.org/TR/2004/REC-xml-20040204/
+ *
+ * for detail.
+ */
+
+#ifndef dom_utils_valid_h_
+#define dom_utils_valid_h_
+
+#include <stdbool.h>
+
+struct dom_string;
+
+bool _dom_validate_name(struct dom_string *name);
+bool _dom_validate_ncname(struct dom_string *name);
+
+#endif
+