From 016dd743cf77b2536015e4e9594716dfdc81d02d Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Wed, 19 Sep 2007 22:06:26 +0000 Subject: Begin implementation of DocumentType class Remove dom_document_set_doctype() -- dom_node_insert_before() (and thus _append_child()) can be used to achieve the same effect. DocumentType node is now a child of the Document node (as it should have been) rather than a hidden field. Make dom_node_destroy() aware of DocumentType nodes potentially having no owner. Make dom_node_finalise() aware of it, too. Make dom_node_get_owner_document() return NULL for Document nodes, as per the spec. Fix bug in dom_node_insert_before() -- previously it failed to catch attempts to insert a second root element. Make dom_node_insert_before() handle DocumentType nodes appropriately. Implement XML binding's dom_implementation_create_document_type() function. Fix XML binding's dom_implementation_create_document() implementation to cope with changed API relating to doctype insertion. Fix up XML parser wrapper to cater for new doctype insertion mechanism. Also sprinkle some NULL about for paranoia purposes. svn path=/trunk/dom/; revision=3551 --- src/core/node.c | 73 ++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 22 deletions(-) (limited to 'src/core/node.c') diff --git a/src/core/node.c b/src/core/node.c index 7dd084f..7dea4f5 100644 --- a/src/core/node.c +++ b/src/core/node.c @@ -14,6 +14,7 @@ #include "core/cdatasection.h" #include "core/comment.h" #include "core/document.h" +#include "core/document_type.h" #include "core/doc_fragment.h" #include "core/element.h" #include "core/entity_ref.h" @@ -39,14 +40,15 @@ void dom_node_destroy(struct dom_node *node) { struct dom_document *owner = node->owner; - bool document_node = (node->type == DOM_DOCUMENT_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(owner != NULL); + assert(null_owner_permitted || owner != NULL); - if (!document_node) { + if (!null_owner_permitted) { /* Claim a reference upon the owning document during * destruction to ensure that the document doesn't get * destroyed before its contents. */ @@ -85,7 +87,7 @@ void dom_node_destroy(struct dom_node *node) dom_document_destroy((struct dom_document *) node); break; case DOM_DOCUMENT_TYPE_NODE: - /** \todo document type node */ + dom_document_type_destroy((struct dom_document_type *) node); break; case DOM_DOCUMENT_FRAGMENT_NODE: dom_document_fragment_destroy(owner, @@ -96,7 +98,7 @@ void dom_node_destroy(struct dom_node *node) break; } - if (!document_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 @@ -173,7 +175,7 @@ dom_exception dom_node_initialise(struct dom_node *node, /** * Finalise a DOM node * - * \param doc The owning document + * \param doc The owning document (or NULL if it's a standalone DocumentType) * \param node The node to finalise * * The contents of ::node will be cleaned up. ::node will not be freed. @@ -183,6 +185,10 @@ void dom_node_finalise(struct dom_document *doc, struct dom_node *node) { 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); + /* Destroy user data */ for (u = node->user_data; u != NULL; u = v) { v = u->next; @@ -493,6 +499,15 @@ dom_exception dom_node_get_attributes(struct dom_node *node, dom_exception dom_node_get_owner_document(struct dom_node *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 + */ + if (node->type == DOM_DOCUMENT_NODE) { + *result = NULL; + + return DOM_NO_ERR; + } + /* If there is an owner, increase its reference count */ if (node->owner != NULL) dom_node_ref((struct dom_node *) node->owner); @@ -522,14 +537,12 @@ dom_exception dom_node_get_owner_document(struct dom_node *node, * DOM_NO_MODIFICATION_ALLOWED_ERR if ::node is readonly, or * ::new_child's parent is readonly, * DOM_NOT_FOUND_ERR if ::ref_child is not a child of - * ::node, - * DOM_NOT_SUPPORTED_ERR if ::node is of type Document and - * ::new_child is of type DocumentType. + * ::node. * * If ::new_child is a DocumentFragment, all of its children are inserted. * If ::new_child is already in the tree, it is first removed. * - * Attempting to insert a node before itself is a NOP + * Attempting to insert a node before itself is a NOP. * * ::new_child's reference count will be increased. The caller should unref * it (as they should already have held a reference on the node) @@ -539,7 +552,11 @@ dom_exception dom_node_insert_before(struct dom_node *node, struct dom_node **result) { /* Ensure that new_child and node are owned by the same document */ - if (new_child->owner != node->owner) + if ((new_child->type == DOM_DOCUMENT_TYPE_NODE && + new_child->owner != NULL && + new_child->owner != node->owner) || + (new_child->type != DOM_DOCUMENT_TYPE_NODE && + new_child->owner != node->owner)) return DOM_WRONG_DOCUMENT_ERR; /** \todo ensure ::node may be written to */ @@ -548,12 +565,6 @@ dom_exception dom_node_insert_before(struct dom_node *node, if (ref_child != NULL && ref_child->parent != node) return DOM_NOT_FOUND_ERR; - /* We don't support addition of DocumentType nodes using this API */ - /** \todo if we did, then we could purge dom_document_set_doctype() */ - if (node->type == DOM_DOCUMENT_NODE && - new_child->type == DOM_DOCUMENT_TYPE_NODE) - return DOM_NOT_SUPPORTED_ERR; - /* Ensure that new_child is not an ancestor of node, nor node itself */ for (struct dom_node *n = node; n != NULL; n = n->parent) { if (n == new_child) @@ -561,7 +572,8 @@ dom_exception dom_node_insert_before(struct dom_node *node, } /* Ensure that the document doesn't already have a root element */ - if (node->type == DOM_DOCUMENT_NODE && node->type == DOM_ELEMENT_NODE) { + if (node->type == DOM_DOCUMENT_NODE && + new_child->type == DOM_ELEMENT_NODE) { for (struct dom_node *n = node->first_child; n != NULL; n = n->next) { if (n->type == DOM_ELEMENT_NODE) @@ -569,8 +581,28 @@ dom_exception dom_node_insert_before(struct dom_node *node, } } + /* Ensure that the document doesn't already have a document type */ + if (node->type == DOM_DOCUMENT_NODE && + new_child->type == DOM_DOCUMENT_TYPE_NODE) { + for (struct dom_node *n = node->first_child; + n != NULL; n = n->next) { + if (n->type == DOM_DOCUMENT_TYPE_NODE) + return DOM_HIERARCHY_REQUEST_ERR; + } + } + /** \todo ensure ::new_child is permitted as a child of ::node */ + /* 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); @@ -761,10 +793,7 @@ dom_exception dom_node_remove_child(struct dom_node *node, * DOM_WRONG_DOCUMENT_ERR if ::new_child was created from a * different document than ::node, * DOM_NO_MODIFICATION_ALLOWED_ERR if ::node is readonly, or - * ::new_child's parent is readonly, - * DOM_NOT_SUPPORTED_ERR if ::node is of type Document and - * ::new_child is of type - * DocumentType or Element. + * ::new_child's parent is readonly. * * If ::new_child is a DocumentFragment, all of its children are inserted. * If ::new_child is already in the tree, it is first removed. -- cgit v1.2.3