diff options
-rw-r--r-- | bindings/xml/xmlbinding.c | 37 | ||||
-rw-r--r-- | bindings/xml/xmlparser.c | 20 | ||||
-rw-r--r-- | include/dom/bootstrap/implpriv.h | 12 | ||||
-rw-r--r-- | src/core/document.c | 51 | ||||
-rw-r--r-- | src/core/document_type.c | 79 | ||||
-rw-r--r-- | src/core/document_type.h | 17 | ||||
-rw-r--r-- | src/core/node.c | 73 |
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. |