summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Mark Bell <jmb@netsurf-browser.org>2007-07-10 23:25:18 +0000
committerJohn Mark Bell <jmb@netsurf-browser.org>2007-07-10 23:25:18 +0000
commit83eff3f08b8a42d89a6eae8ffb7a373016108d76 (patch)
treeb4c493587d97605e69be27b7cd7850ef3bb2a3ac
parentfeed6ef8c3bee2354db4c778dd61ad7e756968e8 (diff)
downloadlibdom-83eff3f08b8a42d89a6eae8ffb7a373016108d76.tar.gz
libdom-83eff3f08b8a42d89a6eae8ffb7a373016108d76.tar.bz2
Add NamedNodeMap.
Minor fix for NodeList unref function; ensure it unrefs the owner document after it has finished using it. svn path=/trunk/dom/; revision=3395
-rw-r--r--include/dom/core/namednodemap.h43
-rw-r--r--src/core/Makefile2
-rw-r--r--src/core/document.c110
-rw-r--r--src/core/document.h12
-rw-r--r--src/core/namednodemap.c345
-rw-r--r--src/core/namednodemap.h39
-rw-r--r--src/core/nodelist.c13
7 files changed, 557 insertions, 7 deletions
diff --git a/include/dom/core/namednodemap.h b/include/dom/core/namednodemap.h
new file mode 100644
index 0000000..511b338
--- /dev/null
+++ b/include/dom/core/namednodemap.h
@@ -0,0 +1,43 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
+ */
+
+#ifndef dom_core_namednodemap_h_
+#define dom_core_namednodemap_h_
+
+#include <dom/core/exceptions.h>
+
+struct dom_node;
+struct dom_namednodemap;
+struct dom_string;
+
+void dom_namednodemap_ref(struct dom_namednodemap *map);
+void dom_namednodemap_unref(struct dom_namednodemap *map);
+
+dom_exception dom_namednodemap_get_length(struct dom_namednodemap *map,
+ unsigned long *length);
+
+dom_exception dom_namednodemap_get_named_item(struct dom_namednodemap *map,
+ struct dom_string *name, struct dom_node **node);
+dom_exception dom_namednodemap_set_named_item(struct dom_namednodemap *map,
+ struct dom_node *arg, struct dom_node **node);
+dom_exception dom_namednodemap_remove_named_item(
+ struct dom_namednodemap *map, struct dom_string *name,
+ struct dom_node **node);
+dom_exception dom_namednodemap_item(struct dom_namednodemap *map,
+ unsigned long index, struct dom_node **node);
+
+dom_exception dom_namednodemap_get_named_item_ns(
+ struct dom_namednodemap *map, struct dom_string *namespace,
+ struct dom_string *localname, struct dom_node **node);
+dom_exception dom_namednodemap_set_named_item_ns(
+ struct dom_namednodemap *map, struct dom_node *arg,
+ struct dom_node **node);
+dom_exception dom_namednodemap_remove_named_item_ns(
+ struct dom_namednodemap *map, struct dom_string *namespace,
+ struct dom_string *localname, struct dom_node **node);
+
+#endif
diff --git a/src/core/Makefile b/src/core/Makefile
index 3245df3..cede355 100644
--- a/src/core/Makefile
+++ b/src/core/Makefile
@@ -22,7 +22,7 @@
CFLAGS += -I$(CURDIR)
# Objects
-OBJS = attr document node nodelist string
+OBJS = attr document namednodemap node nodelist string
.PHONY: clean debug distclean export release setup test
diff --git a/src/core/document.c b/src/core/document.c
index 71b3a6a..102153c 100644
--- a/src/core/document.c
+++ b/src/core/document.c
@@ -24,6 +24,16 @@ struct dom_doc_nl {
};
/**
+ * Iten 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 */
+};
+
+/**
* DOM document
*/
struct dom_document {
@@ -31,6 +41,8 @@ struct dom_document {
struct dom_doc_nl *nodelists; /**< List of active nodelists */
+ struct dom_doc_nnm *maps; /**< List of active namednodemaps */
+
dom_alloc alloc; /**< Memory (de)allocation function */
void *pw; /**< Pointer to client data */
};
@@ -809,7 +821,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;
@@ -849,3 +861,99 @@ void dom_document_remove_nodelist(struct dom_document *doc,
/* And free item */
doc->alloc(l, 0, doc->pw);
}
+
+/**
+ * Get a namednodemap, creating one if necessary
+ *
+ * \param doc The document to get a namednodemap for
+ * \param root Node containing items in map
+ * \param type The type of 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.
+ */
+dom_exception dom_document_get_namednodemap(struct dom_document *doc,
+ struct dom_node *root, dom_namednodemap_type type,
+ struct dom_namednodemap **map)
+{
+ struct dom_doc_nnm *m;
+ dom_exception err;
+
+ for (m = doc->maps; m; m = m->next) {
+ if (dom_namednodemap_match(m->map, root, type))
+ break;
+ }
+
+ if (m != NULL) {
+ /* Found an existing map, so use it */
+ dom_namednodemap_ref(m->map);
+ } else {
+ /* No existing map */
+
+ /* Create active map entry */
+ m = doc->alloc(NULL, sizeof(struct dom_doc_nnm), doc->pw);
+ if (m == NULL)
+ return DOM_NO_MEM_ERR;
+
+ /* Create namednodemap */
+ err = dom_namednodemap_create(doc, root, type, &m->map);
+ if (err != DOM_NO_ERR) {
+ doc->alloc(m, 0, doc->pw);
+ return err;
+ }
+
+ /* 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;
+ }
+
+ /* 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. */
+
+ *map = m->map;
+
+ return DOM_NO_ERR;
+}
+
+/**
+ * Remove a namednodemap
+ *
+ * \param doc The document to remove the map from
+ * \param map The map to remove
+ */
+void dom_document_remove_namednodemap(struct dom_document *doc,
+ struct dom_namednodemap *map)
+{
+ 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 */
+ 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;
+
+ /* And free item */
+ doc->alloc(m, 0, doc->pw);
+}
diff --git a/src/core/document.h b/src/core/document.h
index a51d1e1..236ab4a 100644
--- a/src/core/document.h
+++ b/src/core/document.h
@@ -11,7 +11,10 @@
#include <inttypes.h>
#include <stddef.h>
+#include "core/namednodemap.h"
+
struct dom_document;
+struct dom_namednodemap;
struct dom_node;
struct dom_nodelist;
struct dom_string;
@@ -27,9 +30,16 @@ dom_exception dom_document_get_nodelist(struct dom_document *doc,
struct dom_node *root, struct dom_string *tagname,
struct dom_string *namespace, struct dom_string *localname,
struct dom_nodelist **list);
-
/* Remove a nodelist */
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 *root, dom_namednodemap_type type,
+ struct dom_namednodemap **map);
+/* Remove a namednodemap */
+void dom_document_remove_namednodemap(struct dom_document *doc,
+ struct dom_namednodemap *map);
+
#endif
diff --git a/src/core/namednodemap.c b/src/core/namednodemap.c
new file mode 100644
index 0000000..b13dee6
--- /dev/null
+++ b/src/core/namednodemap.c
@@ -0,0 +1,345 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
+ */
+
+#include <dom/core/node.h>
+
+#include "core/document.h"
+#include "core/namednodemap.h"
+
+#include "utils/utils.h"
+
+/**
+ * DOM named node map
+ */
+struct dom_namednodemap {
+ struct dom_document *owner; /**< Owning document */
+
+ struct dom_node *root; /**< Node containing items in map */
+
+ dom_namednodemap_type type; /**< Type of map */
+
+ uint32_t refcnt; /**< Reference count */
+};
+
+/**
+ * Create a namednodemap
+ *
+ * \param doc The owning document
+ * \param root Node containing items in map
+ * \param type The type of map
+ * \param map Pointer to location to receive created map
+ * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion
+ *
+ * ::root must be a node owned by ::doc and must be either an Element or
+ * DocumentType node.
+ *
+ * If ::root is of type Element, ::type must be DOM_NAMEDNODEMAP_ATTRIBUTES
+ * If ::root is of type DocumentType, ::type may be either
+ * DOM_NAMEDNODEMAP_ENTITIES or DOM_NAMEDNODEMAP_NOTATIONS.
+ *
+ * The returned map will already be referenced, so the client need not
+ * 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 *root, dom_namednodemap_type type,
+ struct dom_namednodemap **map)
+{
+ struct dom_namednodemap *m;
+
+ 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(root);
+ m->root = root;
+
+ m->type = type;
+
+ m->refcnt = 1;
+
+ *map = m;
+
+ return DOM_NO_ERR;
+}
+
+/**
+ * Claim a reference on a DOM named node map
+ *
+ * \param map The map to claim a reference on
+ */
+void dom_namednodemap_ref(struct dom_namednodemap *map)
+{
+ map->refcnt++;
+}
+
+/**
+ * Release a reference on a DOM named node map
+ *
+ * \param map The map to release the reference from
+ *
+ * If the reference count reaches zero, any memory claimed by the
+ * map will be released
+ */
+void dom_namednodemap_unref(struct dom_namednodemap *map)
+{
+ if (--map->refcnt == 0) {
+ struct dom_node *owner = (struct dom_node *) map->owner;
+
+ dom_node_unref(map->root);
+
+ /* Remove map from document */
+ dom_document_remove_namednodemap(map->owner, map);
+
+ /* 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);
+ }
+}
+
+/**
+ * Retrieve the length of a named node map
+ *
+ * \param map Map to retrieve length of
+ * \param length Pointer to location to receive length
+ * \return DOM_NO_ERR.
+ */
+dom_exception dom_namednodemap_get_length(struct dom_namednodemap *map,
+ unsigned long *length)
+{
+ UNUSED(map);
+ UNUSED(length);
+
+ return DOM_NOT_SUPPORTED_ERR;
+}
+
+/**
+ * Retrieve an item by name from a named node map
+ *
+ * \param map The map to retrieve the item from
+ * \param name The name of the item to retrieve
+ * \param node Pointer to location to receive item
+ * \return DOM_NO_ERR.
+ *
+ * The returned node will have had its reference count increased. The client
+ * should unref the node once it has finished with it.
+ */
+dom_exception dom_namednodemap_get_named_item(struct dom_namednodemap *map,
+ struct dom_string *name, struct dom_node **node)
+{
+ UNUSED(map);
+ UNUSED(name);
+ UNUSED(node);
+
+ return DOM_NOT_SUPPORTED_ERR;
+}
+
+/**
+ * Add a node to a named node map, replacing any matching existing node
+ *
+ * \param map The map to add to
+ * \param arg The node to add
+ * \param node Pointer to location to receive replaced node
+ * \return DOM_NO_ERR on success,
+ * DOM_WRONG_DOCUMENT_ERR if ::arg was created from a
+ * different document than ::map,
+ * DOM_NO_MODIFICATION_ALLOWED_ERR if ::map is readonly,
+ * DOM_INUSE_ATTRIBUTE_ERR if ::arg is an Attr that is
+ * already an attribute on another
+ * Element,
+ * DOM_HIERARCHY_REQUEST_ERR if the type of ::arg is not
+ * permitted as a member of ::map.
+ *
+ * ::arg's nodeName attribute will be used to store it in ::map. It will
+ * be accessible using the nodeName attribute as the key for lookup.
+ *
+ * Replacing a node by itself has no effect.
+ *
+ * The returned node will have had its reference count increased. The client
+ * should unref the node once it has finished with it.
+ */
+dom_exception dom_namednodemap_set_named_item(struct dom_namednodemap *map,
+ struct dom_node *arg, struct dom_node **node)
+{
+ UNUSED(map);
+ UNUSED(arg);
+ UNUSED(node);
+
+ return DOM_NOT_SUPPORTED_ERR;
+}
+
+/**
+ * Remove an item by name from a named node map
+ *
+ * \param map The map to remove from
+ * \param name The name of the item to remove
+ * \param node Pointer to location to receive removed item
+ * \return DOM_NO_ERR on success,
+ * DOM_NOT_FOUND_ERR if there is no node named ::name
+ * in ::map,
+ * DOM_NO_MODIFICATION_ALLOWED_ERR if ::map is readonly.
+ *
+ * The returned node will have had its reference count increased. The client
+ * should unref the node once it has finished with it.
+ */
+dom_exception dom_namednodemap_remove_named_item(
+ struct dom_namednodemap *map, struct dom_string *name,
+ struct dom_node **node)
+{
+ UNUSED(map);
+ UNUSED(name);
+ UNUSED(node);
+
+ return DOM_NOT_SUPPORTED_ERR;
+}
+
+/**
+ * Retrieve an item from a named node map
+ *
+ * \param map The map to retrieve the item from
+ * \param index The map index to retrieve
+ * \param node Pointer to location to receive item
+ * \return DOM_NO_ERR.
+ *
+ * ::index is a zero-based index into ::map.
+ * ::index lies in the range [0, length-1]
+ *
+ * The returned node will have had its reference count increased. The client
+ * should unref the node once it has finished with it.
+ */
+dom_exception dom_namednodemap_item(struct dom_namednodemap *map,
+ unsigned long index, struct dom_node **node)
+{
+ UNUSED(map);
+ UNUSED(index);
+ UNUSED(node);
+
+ return DOM_NOT_SUPPORTED_ERR;
+}
+
+/**
+ * Retrieve an item by namespace/localname from a named node map
+ *
+ * \param map The map to retrieve the item from
+ * \param namespace The namespace URI of the item to retrieve
+ * \param localname The local name of the node to retrieve
+ * \param node Pointer to location to receive item
+ * \return DOM_NO_ERR on success,
+ * DOM_NOT_SUPPORTED_ERR if the implementation does not support the
+ * feature "XML" and the language exposed
+ * through the Document does not support
+ * Namespaces.
+ *
+ * The returned node will have had its reference count increased. The client
+ * should unref the node once it has finished with it.
+ */
+dom_exception dom_namednodemap_get_named_item_ns(
+ struct dom_namednodemap *map, struct dom_string *namespace,
+ struct dom_string *localname, struct dom_node **node)
+{
+ UNUSED(map);
+ UNUSED(namespace);
+ UNUSED(localname);
+ UNUSED(node);
+
+ return DOM_NOT_SUPPORTED_ERR;
+}
+
+/**
+ * Add a node to a named node map, replacing any matching existing node
+ *
+ * \param map The map to add to
+ * \param arg The node to add
+ * \param node Pointer to location to receive replaced node
+ * \return DOM_NO_ERR on success,
+ * DOM_WRONG_DOCUMENT_ERR if ::arg was created from a
+ * different document than ::map,
+ * DOM_NO_MODIFICATION_ALLOWED_ERR if ::map is readonly,
+ * DOM_INUSE_ATTRIBUTE_ERR if ::arg is an Attr that is
+ * already an attribute on another
+ * Element,
+ * DOM_HIERARCHY_REQUEST_ERR if the type of ::arg is not
+ * permitted as a member of ::map.
+ * DOM_NOT_SUPPORTED_ERR if the implementation does not support the
+ * feature "XML" and the language exposed
+ * through the Document does not support
+ * Namespaces.
+ *
+ * ::arg's namespaceURI and localName attributes will be used to store it in
+ * ::map. It will be accessible using the namespaceURI and localName
+ * attributes as the keys for lookup.
+ *
+ * Replacing a node by itself has no effect.
+ *
+ * The returned node will have had its reference count increased. The client
+ * should unref the node once it has finished with it.
+ */
+dom_exception dom_namednodemap_set_named_item_ns(
+ struct dom_namednodemap *map, struct dom_node *arg,
+ struct dom_node **node)
+{
+ UNUSED(map);
+ UNUSED(arg);
+ UNUSED(node);
+
+ return DOM_NOT_SUPPORTED_ERR;
+}
+
+/**
+ * Remove an item by namespace/localname from a named node map
+ *
+ * \param map The map to remove from
+ * \param namespace The namespace URI of the item to remove
+ * \param localname The local name of the item to remove
+ * \param node Pointer to location to receive removed item
+ * \return DOM_NO_ERR on success,
+ * DOM_NOT_FOUND_ERR if there is no node named ::name
+ * in ::map,
+ * DOM_NO_MODIFICATION_ALLOWED_ERR if ::map is readonly.
+ * DOM_NOT_SUPPORTED_ERR if the implementation does not support the
+ * feature "XML" and the language exposed
+ * through the Document does not support
+ * Namespaces.
+ *
+ * The returned node will have had its reference count increased. The client
+ * should unref the node once it has finished with it.
+ */
+dom_exception dom_namednodemap_remove_named_item_ns(
+ struct dom_namednodemap *map, struct dom_string *namespace,
+ struct dom_string *localname, struct dom_node **node)
+{
+ UNUSED(map);
+ UNUSED(namespace);
+ UNUSED(localname);
+ UNUSED(node);
+
+ return DOM_NOT_SUPPORTED_ERR;
+}
+
+/**
+ * Match a namednodemap instance against a set of creation parameters
+ *
+ * \param map The map to match
+ * \param root Node containing items in map
+ * \param type The type of map
+ * \return true if list matches, false otherwise
+ */
+bool dom_namednodemap_match(struct dom_namednodemap *map,
+ struct dom_node *root, dom_namednodemap_type type)
+{
+ if (map->root == root && map->type == type)
+ return true;
+
+ return false;
+}
diff --git a/src/core/namednodemap.h b/src/core/namednodemap.h
new file mode 100644
index 0000000..1cd2b0c
--- /dev/null
+++ b/src/core/namednodemap.h
@@ -0,0 +1,39 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
+ */
+
+#ifndef dom_internal_namednodemap_h_
+#define dom_internal_namednodemap_h_
+
+#include <stdbool.h>
+
+#include <dom/core/namednodemap.h>
+
+struct dom_document;
+struct dom_node;
+struct dom_namednodemap;
+struct dom_string;
+
+/**
+ * Type of a named node map
+ */
+typedef enum {
+ DOM_NAMEDNODEMAP_ATTRIBUTES,
+ DOM_NAMEDNODEMAP_ENTITIES,
+ DOM_NAMEDNODEMAP_NOTATIONS
+} dom_namednodemap_type;
+
+/* Create a namednodemap */
+dom_exception dom_namednodemap_create(struct dom_document *doc,
+ struct dom_node *root, dom_namednodemap_type type,
+ struct dom_namednodemap **map);
+
+
+/* Match a namednodemap instance against a set of creation parameters */
+bool dom_namednodemap_match(struct dom_namednodemap *map,
+ struct dom_node *root, dom_namednodemap_type type);
+
+#endif
diff --git a/src/core/nodelist.c b/src/core/nodelist.c
index 1fff561..b37b84e 100644
--- a/src/core/nodelist.c
+++ b/src/core/nodelist.c
@@ -62,7 +62,7 @@ struct dom_nodelist {
* will match the children of ::root.
*
* The returned list will already be referenced, so the client need not
- * do so explicitly. The client should unref the list once finished with it.
+ * 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 *root, struct dom_string *tagname,
@@ -124,6 +124,8 @@ void dom_nodelist_ref(struct dom_nodelist *list)
void dom_nodelist_unref(struct dom_nodelist *list)
{
if (--list->refcnt == 0) {
+ struct dom_node *owner = (struct dom_node *) list->owner;
+
switch (list->type) {
case DOM_NODELIST_CHILDREN:
/* Nothing to do */
@@ -139,13 +141,16 @@ void dom_nodelist_unref(struct dom_nodelist *list)
dom_node_unref(list->root);
- dom_node_unref((struct dom_node *) list->owner);
-
/* Remove list from document */
dom_document_remove_nodelist(list->owner, list);
- /* And destroy the list object */
+ /* Destroy the list object */
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
+ * the document is destroyed before we are */
+ dom_node_unref(owner);
}
}