summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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.