summaryrefslogtreecommitdiff
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
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
-rw-r--r--bindings/xml/xmlbinding.c37
-rw-r--r--bindings/xml/xmlparser.c20
-rw-r--r--include/dom/bootstrap/implpriv.h12
-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
7 files changed, 202 insertions, 87 deletions
diff --git a/bindings/xml/xmlbinding.c b/bindings/xml/xmlbinding.c
index 9809b56..3660015 100644
--- a/bindings/xml/xmlbinding.c
+++ b/bindings/xml/xmlbinding.c
@@ -193,11 +193,7 @@ dom_exception xml_dom_implementation_has_feature(
* \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,
- * DOM_NOT_SUPPORTED_ERR if ::impl does not support the
- * feature "XML" and the language
- * exposed through Document does
- * not support XML namespaces.
+ * DOM_NAMESPACE_ERR if ::qname is malformed.
*
* Any memory allocated by this call should be allocated using
* the provided memory (de)allocation function.
@@ -214,15 +210,23 @@ dom_exception xml_dom_implementation_create_document_type(
struct dom_document_type **doctype,
dom_alloc alloc, void *pw)
{
+ struct dom_document_type *d;
+ dom_exception err;
+
+ /* We have no use for the impl -- we only have one */
UNUSED(impl);
- UNUSED(qname);
- UNUSED(public_id);
- UNUSED(system_id);
- UNUSED(doctype);
- UNUSED(alloc);
- UNUSED(pw);
- return DOM_NOT_SUPPORTED_ERR;
+ /** \todo validate qname */
+
+ /* Create the doctype */
+ err = dom_document_type_create(qname, public_id, system_id,
+ alloc, pw, &d);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ *doctype = d;
+
+ return DOM_NO_ERR;
}
/**
@@ -281,11 +285,18 @@ dom_exception xml_dom_implementation_create_document(
/* Set its doctype, if necessary */
if (doctype != NULL) {
- err = dom_document_set_doctype(d, doctype);
+ struct dom_node *ins_doctype = NULL;
+
+ err = dom_node_append_child((struct dom_node *) d,
+ (struct dom_node *) doctype, &ins_doctype);
if (err != DOM_NO_ERR) {
dom_node_unref((struct dom_node *) d);
return err;
}
+
+ /* Not interested in inserted doctype */
+ if (ins_doctype != NULL)
+ dom_node_unref(ins_doctype);
}
/* Create root element and attach it to document */
diff --git a/bindings/xml/xmlparser.c b/bindings/xml/xmlparser.c
index 93c2506..6f1516b 100644
--- a/bindings/xml/xmlparser.c
+++ b/bindings/xml/xmlparser.c
@@ -637,7 +637,7 @@ void xml_parser_add_node(xml_parser *parser, struct dom_node *parent,
void xml_parser_add_element_node(xml_parser *parser, struct dom_node *parent,
xmlNodePtr child)
{
- struct dom_element *el, *ins_el;
+ struct dom_element *el, *ins_el = NULL;
xmlAttrPtr a;
dom_exception err;
@@ -896,7 +896,7 @@ cleanup:
void xml_parser_add_text_node(xml_parser *parser, struct dom_node *parent,
xmlNodePtr child)
{
- struct dom_text *text, *ins_text;
+ struct dom_text *text, *ins_text = NULL;
struct dom_string *data;
dom_exception err;
@@ -957,7 +957,7 @@ void xml_parser_add_text_node(xml_parser *parser, struct dom_node *parent,
void xml_parser_add_cdata_section(xml_parser *parser,
struct dom_node *parent, xmlNodePtr child)
{
- struct dom_cdata_section *cdata, *ins_cdata;
+ struct dom_cdata_section *cdata, *ins_cdata = NULL;
struct dom_string *data;
dom_exception err;
@@ -1018,7 +1018,7 @@ void xml_parser_add_cdata_section(xml_parser *parser,
void xml_parser_add_entity_reference(xml_parser *parser,
struct dom_node *parent, xmlNodePtr child)
{
- struct dom_entity_reference *entity, *ins_entity;
+ struct dom_entity_reference *entity, *ins_entity = NULL;
struct dom_string *name;
xmlNodePtr c;
dom_exception err;
@@ -1086,7 +1086,7 @@ void xml_parser_add_entity_reference(xml_parser *parser,
void xml_parser_add_comment(xml_parser *parser, struct dom_node *parent,
xmlNodePtr child)
{
- struct dom_comment *comment, *ins_comment;
+ struct dom_comment *comment, *ins_comment = NULL;
struct dom_string *data;
dom_exception err;
@@ -1148,7 +1148,7 @@ void xml_parser_add_document_type(xml_parser *parser,
struct dom_node *parent, xmlNodePtr child)
{
xmlDtdPtr dtd = (xmlDtdPtr) child;
- struct dom_document_type *doctype;
+ struct dom_document_type *doctype, *ins_doctype = NULL;
struct dom_string *qname, *public_id, *system_id;
dom_exception err;
@@ -1207,8 +1207,8 @@ void xml_parser_add_document_type(xml_parser *parser,
dom_string_unref(qname);
/* Add doctype to document */
- err = dom_document_set_doctype((struct dom_document *) parent,
- doctype);
+ err = dom_node_append_child(parent, (struct dom_node *) doctype,
+ (struct dom_node **) &ins_doctype);
if (err != DOM_NO_ERR) {
dom_node_unref((struct dom_node *) doctype);
parser->msg(XML_MSG_CRITICAL, parser->mctx,
@@ -1216,6 +1216,10 @@ void xml_parser_add_document_type(xml_parser *parser,
return;
}
+ /* Not interested in inserted node */
+ if (ins_doctype != NULL)
+ dom_node_unref((struct dom_node *) ins_doctype);
+
/* Link nodes together */
err = xml_parser_link_nodes(parser, (struct dom_node *) doctype,
child);
diff --git a/include/dom/bootstrap/implpriv.h b/include/dom/bootstrap/implpriv.h
index 5c6a820..36359c5 100644
--- a/include/dom/bootstrap/implpriv.h
+++ b/include/dom/bootstrap/implpriv.h
@@ -15,6 +15,9 @@
* The Document implementation includes this as it needs the declaration of
* dom_document_create and dom_document_set_doctype.
*
+ * The DocumentType implementation includes this as it needs the declaration
+ * of dom_document_type_create.
+ *
* No other client should be including this.
*/
@@ -248,8 +251,11 @@ dom_exception dom_register_source(struct dom_implementation_source *source,
dom_exception dom_document_create(struct dom_implementation *impl,
dom_alloc alloc, void *pw, struct dom_document **doc);
-/* Set a Document's DocumentType */
-dom_exception dom_document_set_doctype(struct dom_document *doc,
- struct dom_document_type *doctype);
+/* Create a DOM document type */
+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);
#endif
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.