summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorJohn Mark Bell <jmb@netsurf-browser.org>2007-09-19 22:06:26 +0000
committerJohn Mark Bell <jmb@netsurf-browser.org>2007-09-19 22:06:26 +0000
commitb2256675eaf9cf9fa239da93db4f205d97fc710c (patch)
treef03cc1aae39835468e3e581aa46dcb0e9bc0ff17 /src/core
parent0f66febea8d8f79357a12a102847bf403fd099c9 (diff)
downloadlibdom-b2256675eaf9cf9fa239da93db4f205d97fc710c.tar.gz
libdom-b2256675eaf9cf9fa239da93db4f205d97fc710c.tar.bz2
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
Diffstat (limited to 'src/core')
-rw-r--r--src/core/document.c51
-rw-r--r--src/core/document_type.c79
-rw-r--r--src/core/document_type.h17
-rw-r--r--src/core/node.c73
4 files changed, 157 insertions, 63 deletions
diff --git a/src/core/document.c b/src/core/document.c
index de57f72..d768946 100644
--- a/src/core/document.c
+++ b/src/core/document.c
@@ -55,8 +55,6 @@ struct dom_doc_nnm {
struct dom_document {
struct dom_node base; /**< Base node */
- struct dom_document_type *type; /**< Associated doctype */
-
struct dom_implementation *impl; /**< Owning implementation */
struct dom_doc_nl *nodelists; /**< List of active nodelists */
@@ -157,8 +155,6 @@ dom_exception dom_document_create(struct dom_implementation *impl,
}
/* Initialise remaining type-specific data */
- d->type = NULL;
-
if (impl != NULL)
dom_implementation_ref(impl);
d->impl = impl;
@@ -211,15 +207,6 @@ void dom_document_destroy(struct dom_document *doc)
/* Ok, the document tree is empty, as is the list of nodes pending
* deletion. Therefore, it is safe to destroy the document. */
- /* Destroy the doctype (if there is one) */
- if (doc->type != NULL) {
- ((struct dom_node *) doc->type)->parent = NULL;
-
- dom_node_destroy((struct dom_node *) doc->type);
- }
-
- doc->type = NULL;
-
if (doc->impl != NULL)
dom_implementation_unref(doc->impl);
doc->impl = NULL;
@@ -258,10 +245,17 @@ void dom_document_destroy(struct dom_document *doc)
dom_exception dom_document_get_doctype(struct dom_document *doc,
struct dom_document_type **result)
{
- if (doc->type != NULL)
- dom_node_ref((struct dom_node *) doc->type);
+ struct dom_node *c;
- *result = doc->type;
+ for (c = doc->base.first_child; c != NULL; c = c->next) {
+ if (c->type == DOM_DOCUMENT_TYPE_NODE)
+ break;
+ }
+
+ if (c != NULL)
+ dom_node_ref(c);
+
+ *result = (struct dom_document_type *) c;
return DOM_NO_ERR;
}
@@ -941,31 +935,6 @@ dom_exception dom_document_rename_node(struct dom_document *doc,
/* */
/**
- * Set a Document's Document Type
- *
- * \param doc Document to set type of
- * \param doctype The doctype to apply
- * \return DOM_NO_ERR on success,
- * DOM_INVALID_MODIFICATION_ERR if ::doc already has a doctype.
- *
- * The doctype will have its reference count increased. It is the
- * responsibility of the caller to unref the doctype once it has finished
- * with it.
- */
-dom_exception dom_document_set_doctype(struct dom_document *doc,
- struct dom_document_type *doctype)
-{
- UNUSED(doc);
- UNUSED(doctype);
-
- return DOM_NOT_SUPPORTED_ERR;
-}
-
-/* */
-/* ----------------------------------------------------------------------- */
-/* */
-
-/**
* Acquire a pointer to the base of the document buffer
*
* \param doc Document to retrieve pointer from
diff --git a/src/core/document_type.c b/src/core/document_type.c
index 2bd0f5b..30d8fe2 100644
--- a/src/core/document_type.c
+++ b/src/core/document_type.c
@@ -7,7 +7,10 @@
*/
#include <dom/core/document_type.h>
+#include <dom/core/string.h>
+#include <dom/bootstrap/implpriv.h>
+#include "core/document_type.h"
#include "core/node.h"
#include "utils/utils.h"
@@ -18,9 +21,85 @@ struct dom_document_type {
struct dom_node base; /**< Base node */
/** \todo other members */
+ 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 */
};
/**
+ * Create a document type node
+ *
+ * \param qname The qualified name of the document type
+ * \param public_id The external subset public identifier
+ * \param system_id The external subset system identifier
+ * \param alloc Memory (de)allocation function
+ * \param pw Pointer to client-specific private data
+ * \param doctype Pointer to location to receive result
+ * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion.
+ *
+ * The doctype will be referenced, so the client need not do so
+ * explicitly. The client must unref the doctype once it has
+ * finished with it.
+ */
+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)
+{
+ struct dom_document_type *result;
+ dom_exception err;
+
+ /* Create node */
+ result = alloc(NULL, sizeof(struct dom_document_type), pw);
+ if (result == NULL)
+ return DOM_NO_MEM_ERR;
+
+ /* Initialise base node */
+ err = dom_node_initialise(&result->base, NULL, DOM_DOCUMENT_TYPE_NODE,
+ qname, NULL);
+ if (err != DOM_NO_ERR) {
+ alloc(result, 0, pw);
+ return err;
+ }
+
+ /* 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;
+
+ *doctype = result;
+
+ return DOM_NO_ERR;
+}
+
+/**
+ * Destroy a DocumentType node
+ *
+ * \param doctype The DocumentType node to destroy
+ *
+ * The contents of ::doctype will be destroyed and ::doctype will be freed.
+ */
+void dom_document_type_destroy(struct dom_document_type *doctype)
+{
+ /* 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);
+
+ /* Free doctype */
+ doctype->alloc(doctype, 0, doctype->pw);
+}
+
+/**
* Retrieve a document type's name
*
* \param doc_type Document type to retrieve name from
diff --git a/src/core/document_type.h b/src/core/document_type.h
new file mode 100644
index 0000000..266a1b6
--- /dev/null
+++ b/src/core/document_type.h
@@ -0,0 +1,17 @@
+/*
+ * 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_core_document_type_h_
+#define dom_internal_core_document_type_h_
+
+struct dom_document_type;
+
+/* Destroy a document type */
+void dom_document_type_destroy(struct dom_document_type *doctype);
+
+#endif
+
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.