summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-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
34 files changed, 5487 insertions, 1914 deletions
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;
+}
+