Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * This file is part of libdom.
  3.  * Licensed under the MIT License,
  4.  *                http://www.opensource.org/licenses/mit-license.php
  5.  * Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
  6.  * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
  7.  */
  8.  
  9. #include <assert.h>
  10. #include <stdlib.h>
  11.  
  12. typedef signed char int8_t;
  13. typedef signed short int16_t;
  14. typedef signed int int32_t;
  15.  
  16. typedef unsigned char uint8_t;
  17. typedef unsigned short uint16_t;
  18. typedef unsigned int uint32_t;
  19.  
  20. #include <dom/functypes.h>
  21. #include <dom/core/attr.h>
  22. #include <dom/core/element.h>
  23. #include <dom/core/document.h>
  24. #include <dom/core/implementation.h>
  25.  
  26.  
  27.  
  28.  
  29. #include "core/string.h"
  30. #include "core/attr.h"
  31. #include "core/cdatasection.h"
  32. #include "core/comment.h"
  33. #include "core/document.h"
  34. #include "core/doc_fragment.h"
  35. #include "core/element.h"
  36. #include "core/entity_ref.h"
  37. #include "core/namednodemap.h"
  38. #include "core/nodelist.h"
  39. #include "core/pi.h"
  40. #include "core/text.h"
  41. #include "utils/validate.h"
  42. #include "utils/namespace.h"
  43. #include "utils/utils.h"
  44.  
  45. /**
  46.  * Item in list of active nodelists
  47.  */
  48. struct dom_doc_nl {
  49.         dom_nodelist *list;     /**< Nodelist */
  50.  
  51.         struct dom_doc_nl *next;        /**< Next item */
  52.         struct dom_doc_nl *prev;        /**< Previous item */
  53. };
  54.  
  55. /* The virtual functions of this dom_document */
  56. static struct dom_document_vtable document_vtable = {
  57.         {
  58.                 {
  59.                         DOM_NODE_EVENT_TARGET_VTABLE
  60.                 },
  61.                 DOM_NODE_VTABLE_DOCUMENT
  62.         },
  63.         DOM_DOCUMENT_VTABLE
  64. };
  65.  
  66. static struct dom_node_protect_vtable document_protect_vtable = {
  67.         DOM_DOCUMENT_PROTECT_VTABLE
  68. };
  69.  
  70.  
  71. /*----------------------------------------------------------------------*/
  72.  
  73. /* Internally used helper functions */
  74. static dom_exception dom_document_dup_node(dom_document *doc,
  75.                 dom_node *node, bool deep, dom_node **result,
  76.                 dom_node_operation opt);
  77.  
  78.  
  79. /*----------------------------------------------------------------------*/
  80.  
  81. /* The constructors and destructors */
  82.  
  83. /**
  84.  * Create a Document
  85.  *
  86.  * \param doc    Pointer to location to receive created document
  87.  * \param daf    The default action fetcher
  88.  * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion.
  89.  *
  90.  * The returned document will already be referenced.
  91.  */
  92. dom_exception _dom_document_create(dom_events_default_action_fetcher daf,
  93.                                    void *daf_ctx,
  94.                                    dom_document **doc)
  95. {
  96.         dom_document *d;
  97.         dom_exception err;
  98.  
  99.         /* Create document */
  100.         d = malloc(sizeof(dom_document));
  101.         if (d == NULL)
  102.                 return DOM_NO_MEM_ERR;
  103.  
  104.         /* Initialise the virtual table */
  105.         d->base.base.vtable = &document_vtable;
  106.         d->base.vtable = &document_protect_vtable;
  107.  
  108.         /* Initialise base class -- the Document has no parent, so
  109.          * destruction will be attempted as soon as its reference count
  110.          * reaches zero. Documents own themselves (this simplifies the
  111.          * rest of the code, as it doesn't need to special case Documents)
  112.          */
  113.         err = _dom_document_initialise(d, daf, daf_ctx);
  114.         if (err != DOM_NO_ERR) {
  115.                 /* Clean up document */
  116.                 free(d);
  117.                 return err;
  118.         }
  119.  
  120.         *doc = d;
  121.  
  122.         return DOM_NO_ERR;
  123. }
  124.  
  125. /* Initialise the document */
  126. dom_exception _dom_document_initialise(dom_document *doc,
  127.                                        dom_events_default_action_fetcher daf,
  128.                                        void *daf_ctx)
  129. {
  130.         dom_exception err;
  131.         dom_string *name;
  132.  
  133.         err = dom_string_create((const uint8_t *) "#document",
  134.                         SLEN("#document"), &name);
  135.         if (err != DOM_NO_ERR)
  136.                 return err;
  137.  
  138.         doc->nodelists = NULL;
  139.  
  140.         err = _dom_node_initialise(&doc->base, doc, DOM_DOCUMENT_NODE,
  141.                         name, NULL, NULL, NULL);
  142.         dom_string_unref(name);
  143.         if (err != DOM_NO_ERR)
  144.           return err;
  145.  
  146.         list_init(&doc->pending_nodes);
  147.  
  148.         err = dom_string_create_interned((const uint8_t *) "id",
  149.                                          SLEN("id"), &doc->id_name);
  150.         if (err != DOM_NO_ERR)
  151.                 return err;
  152.         doc->quirks = DOM_DOCUMENT_QUIRKS_MODE_NONE;
  153.  
  154.         err = dom_string_create_interned((const uint8_t *) "class",
  155.                         SLEN("class"), &doc->class_string);
  156.         if (err != DOM_NO_ERR) {
  157.                 dom_string_unref(doc->id_name);
  158.                 return err;
  159.         }
  160.  
  161.         /* Intern the empty string. The use of a space in the constant
  162.          * is to prevent the compiler warning about an empty string.
  163.          */
  164.         err = dom_string_create_interned((const uint8_t *) " ", 0,
  165.                                          &doc->_memo_empty);
  166.         if (err != DOM_NO_ERR) {
  167.                 dom_string_unref(doc->id_name);
  168.                 dom_string_unref(doc->class_string);
  169.                 return err;
  170.         }
  171.  
  172.         err = dom_string_create_interned((const uint8_t *) "DOMNodeInserted",
  173.                                          SLEN("DOMNodeInserted"),
  174.                                          &doc->_memo_domnodeinserted);
  175.         if (err != DOM_NO_ERR) {
  176.                 dom_string_unref(doc->_memo_empty);
  177.                 dom_string_unref(doc->id_name);
  178.                 dom_string_unref(doc->class_string);
  179.                 return err;
  180.         }
  181.  
  182.         err = dom_string_create_interned((const uint8_t *) "DOMNodeRemoved",
  183.                                          SLEN("DOMNodeRemoved"),
  184.                                          &doc->_memo_domnoderemoved);
  185.         if (err != DOM_NO_ERR) {
  186.                 dom_string_unref(doc->_memo_domnodeinserted);
  187.                 dom_string_unref(doc->_memo_empty);
  188.                 dom_string_unref(doc->id_name);
  189.                 dom_string_unref(doc->class_string);
  190.                 return err;
  191.         }
  192.  
  193.         err = dom_string_create_interned((const uint8_t *) "DOMNodeInsertedIntoDocument",
  194.                                          SLEN("DOMNodeInsertedIntoDocument"),
  195.                                          &doc->_memo_domnodeinsertedintodocument);
  196.         if (err != DOM_NO_ERR) {
  197.                 dom_string_unref(doc->_memo_domnoderemoved);
  198.                 dom_string_unref(doc->_memo_domnodeinserted);
  199.                 dom_string_unref(doc->_memo_empty);
  200.                 dom_string_unref(doc->id_name);
  201.                 dom_string_unref(doc->class_string);
  202.                 return err;
  203.         }
  204.  
  205.         err = dom_string_create_interned((const uint8_t *) "DOMNodeRemovedFromDocument",
  206.                                          SLEN("DOMNodeRemovedFromDocument"),
  207.                                          &doc->_memo_domnoderemovedfromdocument);
  208.         if (err != DOM_NO_ERR) {
  209.                 dom_string_unref(doc->_memo_domnodeinsertedintodocument);
  210.                 dom_string_unref(doc->_memo_domnoderemoved);
  211.                 dom_string_unref(doc->_memo_domnodeinserted);
  212.                 dom_string_unref(doc->_memo_empty);
  213.                 dom_string_unref(doc->id_name);
  214.                 dom_string_unref(doc->class_string);
  215.                 return err;
  216.         }
  217.  
  218.         err = dom_string_create_interned((const uint8_t *) "DOMAttrModified",
  219.                                          SLEN("DOMAttrModified"),
  220.                                          &doc->_memo_domattrmodified);
  221.         if (err != DOM_NO_ERR) {
  222.                 dom_string_unref(doc->_memo_domnoderemovedfromdocument);
  223.                 dom_string_unref(doc->_memo_domnodeinsertedintodocument);
  224.                 dom_string_unref(doc->_memo_domnoderemoved);
  225.                 dom_string_unref(doc->_memo_domnodeinserted);
  226.                 dom_string_unref(doc->_memo_empty);
  227.                 dom_string_unref(doc->id_name);
  228.                 dom_string_unref(doc->class_string);
  229.                 return err;
  230.         }
  231.  
  232.         err = dom_string_create_interned((const uint8_t *) "DOMCharacterDataModified",
  233.                                          SLEN("DOMCharacterDataModified"),
  234.                                          &doc->_memo_domcharacterdatamodified);
  235.         if (err != DOM_NO_ERR) {
  236.                 dom_string_unref(doc->_memo_domattrmodified);
  237.                 dom_string_unref(doc->_memo_domnoderemovedfromdocument);
  238.                 dom_string_unref(doc->_memo_domnodeinsertedintodocument);
  239.                 dom_string_unref(doc->_memo_domnoderemoved);
  240.                 dom_string_unref(doc->_memo_domnodeinserted);
  241.                 dom_string_unref(doc->_memo_empty);
  242.                 dom_string_unref(doc->id_name);
  243.                 dom_string_unref(doc->class_string);
  244.                 return err;
  245.         }
  246.  
  247.         err = dom_string_create_interned((const uint8_t *) "DOMSubtreeModified",
  248.                                          SLEN("DOMSubtreeModified"),
  249.                                          &doc->_memo_domsubtreemodified);
  250.         if (err != DOM_NO_ERR) {
  251.                 dom_string_unref(doc->_memo_domcharacterdatamodified);
  252.                 dom_string_unref(doc->_memo_domattrmodified);
  253.                 dom_string_unref(doc->_memo_domnoderemovedfromdocument);
  254.                 dom_string_unref(doc->_memo_domnodeinsertedintodocument);
  255.                 dom_string_unref(doc->_memo_domnoderemoved);
  256.                 dom_string_unref(doc->_memo_domnodeinserted);
  257.                 dom_string_unref(doc->_memo_empty);
  258.                 dom_string_unref(doc->id_name);
  259.                 dom_string_unref(doc->class_string);
  260.                 return err;
  261.         }
  262.  
  263.         /* We should not pass a NULL when all things hook up */
  264.         return _dom_document_event_internal_initialise(doc, &doc->dei, daf, daf_ctx);
  265. }
  266.  
  267.  
  268. /* Finalise the document */
  269. bool _dom_document_finalise(dom_document *doc)
  270. {
  271.         /* Finalise base class, delete the tree in force */
  272.         _dom_node_finalise(&doc->base);
  273.  
  274.         /* Now, the first_child and last_child should be null */
  275.         doc->base.first_child = NULL;
  276.         doc->base.last_child = NULL;
  277.  
  278.         /* Ensure list of nodes pending deletion is empty. If not,
  279.          * then we can't yet destroy the document (its destruction will
  280.          * have to wait until the pending nodes are destroyed) */
  281.         if (doc->pending_nodes.next != &doc->pending_nodes)
  282.                 return false;
  283.  
  284.         /* Ok, the document tree is empty, as is the list of nodes pending
  285.          * deletion. Therefore, it is safe to destroy the document. */
  286.  
  287.         /* This is paranoia -- if there are any remaining nodelists,
  288.          * then the document's reference count will be
  289.          * non-zero as these data structures reference the document because
  290.          * they are held by the client. */
  291.         doc->nodelists = NULL;
  292.  
  293.         if (doc->id_name != NULL)
  294.                 dom_string_unref(doc->id_name);
  295.  
  296.         dom_string_unref(doc->class_string);
  297.         dom_string_unref(doc->_memo_empty);
  298.         dom_string_unref(doc->_memo_domnodeinserted);
  299.         dom_string_unref(doc->_memo_domnoderemoved);
  300.         dom_string_unref(doc->_memo_domnodeinsertedintodocument);
  301.         dom_string_unref(doc->_memo_domnoderemovedfromdocument);
  302.         dom_string_unref(doc->_memo_domattrmodified);
  303.         dom_string_unref(doc->_memo_domcharacterdatamodified);
  304.         dom_string_unref(doc->_memo_domsubtreemodified);
  305.        
  306.         _dom_document_event_internal_finalise(doc, &doc->dei);
  307.  
  308.         return true;
  309. }
  310.  
  311.  
  312.  
  313. /*----------------------------------------------------------------------*/
  314.  
  315. /* Public virtual functions */
  316.  
  317. /**
  318.  * Retrieve the doctype of a document
  319.  *
  320.  * \param doc     The document to retrieve the doctype from
  321.  * \param result  Pointer to location to receive result
  322.  * \return DOM_NO_ERR.
  323.  *
  324.  * The returned node will have its reference count increased. It is
  325.  * the responsibility of the caller to unref the node once it has
  326.  * finished with it.
  327.  */
  328. dom_exception _dom_document_get_doctype(dom_document *doc,
  329.                 dom_document_type **result)
  330. {
  331.         dom_node_internal *c;
  332.  
  333.         for (c = doc->base.first_child; c != NULL; c = c->next) {
  334.                 if (c->type == DOM_DOCUMENT_TYPE_NODE)
  335.                         break;
  336.         }
  337.  
  338.         if (c != NULL)
  339.                 dom_node_ref(c);
  340.  
  341.         *result = (dom_document_type *) c;
  342.  
  343.         return DOM_NO_ERR;
  344. }
  345.  
  346. /**
  347.  * Retrieve the DOM implementation that handles this document
  348.  *
  349.  * \param doc     The document to retrieve the implementation from
  350.  * \param result  Pointer to location to receive result
  351.  * \return DOM_NO_ERR.
  352.  *
  353.  * The returned implementation will have its reference count increased.
  354.  * It is the responsibility of the caller to unref the implementation once
  355.  * it has finished with it.
  356.  */
  357. dom_exception _dom_document_get_implementation(dom_document *doc,
  358.                 dom_implementation **result)
  359. {
  360.         UNUSED(doc);
  361.  
  362.         *result = (dom_implementation *) "libdom";
  363.  
  364.         return DOM_NO_ERR;
  365. }
  366.  
  367. /**
  368.  * Retrieve the document element of a document
  369.  *
  370.  * \param doc     The document to retrieve the document element from
  371.  * \param result  Pointer to location to receive result
  372.  * \return DOM_NO_ERR.
  373.  *
  374.  * The returned node will have its reference count increased. It is
  375.  * the responsibility of the caller to unref the node once it has
  376.  * finished with it.
  377.  */
  378. dom_exception _dom_document_get_document_element(dom_document *doc,
  379.                 dom_element **result)
  380. {
  381.         dom_node_internal *root;
  382.  
  383.         /* Find the first element node in child list */
  384.         for (root = doc->base.first_child; root != NULL; root = root->next) {
  385.                 if (root->type == DOM_ELEMENT_NODE)
  386.                         break;
  387.         }
  388.  
  389.         if (root != NULL)
  390.                 dom_node_ref(root);
  391.  
  392.         *result = (dom_element *) root;
  393.  
  394.         return DOM_NO_ERR;
  395. }
  396.  
  397. /**
  398.  * Create an element
  399.  *
  400.  * \param doc       The document owning the element
  401.  * \param tag_name  The name of the element
  402.  * \param result    Pointer to location to receive result
  403.  * \return DOM_NO_ERR                on success,
  404.  *         DOM_INVALID_CHARACTER_ERR if ::tag_name is invalid.
  405.  *
  406.  * ::doc and ::tag_name will have their reference counts increased.
  407.  *
  408.  * The returned node will have its reference count increased. It is
  409.  * the responsibility of the caller to unref the node once it has
  410.  * finished with it.
  411.  */
  412. dom_exception _dom_document_create_element(dom_document *doc,
  413.                 dom_string *tag_name, dom_element **result)
  414. {
  415.         if (_dom_validate_name(tag_name) == false)
  416.                 return DOM_INVALID_CHARACTER_ERR;
  417.  
  418.         return _dom_element_create(doc, tag_name, NULL, NULL, result);
  419. }
  420.  
  421. /**
  422.  * Create a document fragment
  423.  *
  424.  * \param doc     The document owning the fragment
  425.  * \param result  Pointer to location to receive result
  426.  * \return DOM_NO_ERR.
  427.  *
  428.  * The returned node will have its reference count increased. It is
  429.  * the responsibility of the caller to unref the node once it has
  430.  * finished with it.
  431.  */
  432. dom_exception _dom_document_create_document_fragment(dom_document *doc,
  433.                 dom_document_fragment **result)
  434. {
  435.         dom_string *name;
  436.         dom_exception err;
  437.  
  438.         err = dom_string_create((const uint8_t *) "#document-fragment",
  439.                         SLEN("#document-fragment"), &name);
  440.         if (err != DOM_NO_ERR)
  441.                 return err;
  442.        
  443.         err = _dom_document_fragment_create(doc, name, NULL, result);
  444.         dom_string_unref(name);
  445.  
  446.         return err;
  447. }
  448.  
  449. /**
  450.  * Create a text node
  451.  *
  452.  * \param doc     The document owning the node
  453.  * \param data    The data for the node
  454.  * \param result  Pointer to location to receive result
  455.  * \return DOM_NO_ERR.
  456.  *
  457.  * The returned node will have its reference count increased. It is
  458.  * the responsibility of the caller to unref the node once it has
  459.  * finished with it.
  460.  */
  461. dom_exception _dom_document_create_text_node(dom_document *doc,
  462.                 dom_string *data, dom_text **result)
  463. {
  464.         dom_string *name;
  465.         dom_exception err;
  466.  
  467.         err = dom_string_create((const uint8_t *) "#text",
  468.                         SLEN("#text"), &name);
  469.         if (err != DOM_NO_ERR)
  470.                 return err;
  471.        
  472.         err = _dom_text_create(doc, name, data, result);
  473.         dom_string_unref(name);
  474.  
  475.         return err;
  476. }
  477.  
  478. /**
  479.  * Create a comment node
  480.  *
  481.  * \param doc     The document owning the node
  482.  * \param data    The data for the node
  483.  * \param result  Pointer to location to receive result
  484.  * \return DOM_NO_ERR.
  485.  *
  486.  * The returned node will have its reference count increased. It is
  487.  * the responsibility of the caller to unref the node once it has
  488.  * finished with it.
  489.  */
  490. dom_exception _dom_document_create_comment(dom_document *doc,
  491.                 dom_string *data, dom_comment **result)
  492. {
  493.         dom_string *name;
  494.         dom_exception err;
  495.  
  496.         err = dom_string_create((const uint8_t *) "#comment", SLEN("#comment"),
  497.                         &name);
  498.         if (err != DOM_NO_ERR)
  499.                 return err;
  500.        
  501.         err = _dom_comment_create(doc, name, data, result);
  502.         dom_string_unref(name);
  503.  
  504.         return err;
  505. }
  506.  
  507. /**
  508.  * Create a CDATA section
  509.  *
  510.  * \param doc     The document owning the section
  511.  * \param data    The data for the section contents
  512.  * \param result  Pointer to location to receive result
  513.  * \return DOM_NO_ERR            on success,
  514.  *         DOM_NOT_SUPPORTED_ERR if this is an HTML document.
  515.  *
  516.  * The returned node will have its reference count increased. It is
  517.  * the responsibility of the caller to unref the node once it has
  518.  * finished with it.
  519.  */
  520. dom_exception _dom_document_create_cdata_section(dom_document *doc,
  521.                 dom_string *data, dom_cdata_section **result)
  522. {
  523.         dom_string *name;
  524.         dom_exception err;
  525.  
  526.         err = dom_string_create((const uint8_t *) "#cdata-section",
  527.                         SLEN("#cdata-section"), &name);
  528.         if (err != DOM_NO_ERR)
  529.                 return err;
  530.  
  531.         err = _dom_cdata_section_create(doc, name, data, result);
  532.         dom_string_unref(name);
  533.  
  534.         return err;
  535. }
  536.  
  537. /**
  538.  * Create a processing instruction
  539.  *
  540.  * \param doc     The document owning the instruction
  541.  * \param target  The instruction target
  542.  * \param data    The data for the node
  543.  * \param result  Pointer to location to receive result
  544.  * \return DOM_NO_ERR                on success,
  545.  *         DOM_INVALID_CHARACTER_ERR if ::target is invalid,
  546.  *         DOM_NOT_SUPPORTED_ERR     if this is an HTML document.
  547.  *
  548.  * The returned node will have its reference count increased. It is
  549.  * the responsibility of the caller to unref the node once it has
  550.  * finished with it.
  551.  */
  552. dom_exception _dom_document_create_processing_instruction(
  553.                 dom_document *doc, dom_string *target,
  554.                 dom_string *data,
  555.                 dom_processing_instruction **result)
  556. {
  557.         if (_dom_validate_name(target) == false)
  558.                 return DOM_INVALID_CHARACTER_ERR;
  559.  
  560.         return _dom_processing_instruction_create(doc, target, data, result);
  561. }
  562.  
  563. /**
  564.  * Create an attribute
  565.  *
  566.  * \param doc     The document owning the attribute
  567.  * \param name    The name of the attribute
  568.  * \param result  Pointer to location to receive result
  569.  * \return DOM_NO_ERR                on success,
  570.  *         DOM_INVALID_CHARACTER_ERR if ::name is invalid.
  571.  *
  572.  * The constructed attribute will always be classified as 'specified'.
  573.  *
  574.  * The returned node will have its reference count increased. It is
  575.  * the responsibility of the caller to unref the node once it has
  576.  * finished with it.
  577.  */
  578. dom_exception _dom_document_create_attribute(dom_document *doc,
  579.                 dom_string *name, dom_attr **result)
  580. {
  581.         if (_dom_validate_name(name) == false)
  582.                 return DOM_INVALID_CHARACTER_ERR;
  583.  
  584.         return _dom_attr_create(doc, name, NULL, NULL, true, result);
  585. }
  586.  
  587. /**
  588.  * Create an entity reference
  589.  *
  590.  * \param doc     The document owning the reference
  591.  * \param name    The name of the entity to reference
  592.  * \param result  Pointer to location to receive result
  593.  * \return DOM_NO_ERR                on success,
  594.  *         DOM_INVALID_CHARACTER_ERR if ::name is invalid,
  595.  *         DOM_NOT_SUPPORTED_ERR     if this is an HTML document.
  596.  *
  597.  * The returned node will have its reference count increased. It is
  598.  * the responsibility of the caller to unref the node once it has
  599.  * finished with it.
  600.  */
  601. dom_exception _dom_document_create_entity_reference(dom_document *doc,
  602.                 dom_string *name,
  603.                 dom_entity_reference **result)
  604. {
  605.         if (_dom_validate_name(name) == false)
  606.                 return DOM_INVALID_CHARACTER_ERR;
  607.  
  608.         return _dom_entity_reference_create(doc, name, NULL, result);
  609. }
  610.  
  611. /**
  612.  * Retrieve a list of all elements with a given tag name
  613.  *
  614.  * \param doc      The document to search in
  615.  * \param tagname  The tag name to search for ("*" for all)
  616.  * \param result   Pointer to location to receive result
  617.  * \return DOM_NO_ERR.
  618.  *
  619.  * The returned list will have its reference count increased. It is
  620.  * the responsibility of the caller to unref the list once it has
  621.  * finished with it.
  622.  */
  623. dom_exception _dom_document_get_elements_by_tag_name(dom_document *doc,
  624.                 dom_string *tagname, dom_nodelist **result)
  625. {
  626.         return _dom_document_get_nodelist(doc, DOM_NODELIST_BY_NAME,
  627.                         (dom_node_internal *) doc,  tagname, NULL, NULL,
  628.                         result);
  629. }
  630.  
  631. /**
  632.  * Import a node from another document into this one
  633.  *
  634.  * \param doc     The document to import into
  635.  * \param node    The node to import
  636.  * \param deep    Whether to copy the node's subtree
  637.  * \param result  Pointer to location to receive imported node in this document.
  638.  * \return DOM_NO_ERR                on success,
  639.  *         DOM_INVALID_CHARACTER_ERR if any of the names are invalid,
  640.  *         DOM_NOT_SUPPORTED_ERR     if the type of ::node is unsupported
  641.  *
  642.  * The returned node will have its reference count increased. It is
  643.  * the responsibility of the caller to unref the node once it has
  644.  * finished with it.
  645.  */
  646. dom_exception _dom_document_import_node(dom_document *doc,
  647.                 dom_node *node, bool deep, dom_node **result)
  648. {
  649.         /* TODO: The DOM_INVALID_CHARACTER_ERR exception */
  650.  
  651.         return dom_document_dup_node(doc, node, deep, result,
  652.                         DOM_NODE_IMPORTED);
  653. }
  654.  
  655. /**
  656.  * Create an element from the qualified name and namespace URI
  657.  *
  658.  * \param doc        The document owning the element
  659.  * \param namespace  The namespace URI to use, or NULL for none
  660.  * \param qname      The qualified name of the element
  661.  * \param result     Pointer to location to receive result
  662.  * \return DOM_NO_ERR                on success,
  663.  *         DOM_INVALID_CHARACTER_ERR if ::qname is invalid,
  664.  *         DOM_NAMESPACE_ERR         if ::qname is malformed, or it has a
  665.  *                                   prefix and ::namespace is NULL, or
  666.  *                                   ::qname has a prefix "xml" and
  667.  *                                   ::namespace is not
  668.  *                                   "http://www.w3.org/XML/1998/namespace",
  669.  *                                   or ::qname has a prefix "xmlns" and
  670.  *                                   ::namespace is not
  671.  *                                   "http://www.w3.org/2000/xmlns", or
  672.  *                                   ::namespace is
  673.  *                                   "http://www.w3.org/2000/xmlns" and
  674.  *                                   ::qname is not (or is not prefixed by)
  675.  *                                   "xmlns",
  676.  *         DOM_NOT_SUPPORTED_ERR     if ::doc does not support the "XML"
  677.  *                                   feature.
  678.  *
  679.  * The returned node will have its reference count increased. It is
  680.  * the responsibility of the caller to unref the node once it has
  681.  * finished with it.
  682.  */
  683. dom_exception _dom_document_create_element_ns(dom_document *doc,
  684.                 dom_string *namespace, dom_string *qname,
  685.                 dom_element **result)
  686. {
  687.         dom_string *prefix, *localname;
  688.         dom_exception err;
  689.  
  690.         if (_dom_validate_name(qname) == false)
  691.                 return DOM_INVALID_CHARACTER_ERR;
  692.  
  693.         /* Validate qname */
  694.         err = _dom_namespace_validate_qname(qname, namespace);
  695.         if (err != DOM_NO_ERR) {
  696.                 return err;
  697.         }
  698.  
  699.         /* Divide QName into prefix/localname pair */
  700.         err = _dom_namespace_split_qname(qname, &prefix, &localname);
  701.         if (err != DOM_NO_ERR) {
  702.                 return err;
  703.         }
  704.  
  705.         /* Attempt to create element */
  706.         err = _dom_element_create(doc, localname, namespace, prefix, result);
  707.  
  708.         /* Tidy up */
  709.         if (localname != NULL) {
  710.                 dom_string_unref(localname);
  711.         }
  712.  
  713.         if (prefix != NULL) {
  714.                 dom_string_unref(prefix);
  715.         }
  716.  
  717.         return err;
  718. }
  719.  
  720. /**
  721.  * Create an attribute from the qualified name and namespace URI
  722.  *
  723.  * \param doc        The document owning the attribute
  724.  * \param namespace  The namespace URI to use
  725.  * \param qname      The qualified name of the attribute
  726.  * \param result     Pointer to location to receive result
  727.  * \return DOM_NO_ERR                on success,
  728.  *         DOM_INVALID_CHARACTER_ERR if ::qname is invalid,
  729.  *         DOM_NAMESPACE_ERR         if ::qname is malformed, or it has a
  730.  *                                   prefix and ::namespace is NULL, or
  731.  *                                   ::qname has a prefix "xml" and
  732.  *                                   ::namespace is not
  733.  *                                   "http://www.w3.org/XML/1998/namespace",
  734.  *                                   or ::qname has a prefix "xmlns" and
  735.  *                                   ::namespace is not
  736.  *                                   "http://www.w3.org/2000/xmlns", or
  737.  *                                   ::namespace is
  738.  *                                   "http://www.w3.org/2000/xmlns" and
  739.  *                                   ::qname is not (or is not prefixed by)
  740.  *                                   "xmlns",
  741.  *         DOM_NOT_SUPPORTED_ERR     if ::doc does not support the "XML"
  742.  *                                   feature.
  743.  *
  744.  * The returned node will have its reference count increased. It is
  745.  * the responsibility of the caller to unref the node once it has
  746.  * finished with it.
  747.  */
  748. dom_exception _dom_document_create_attribute_ns(dom_document *doc,
  749.                 dom_string *namespace, dom_string *qname,
  750.                 dom_attr **result)
  751. {
  752.         dom_string *prefix, *localname;
  753.         dom_exception err;
  754.  
  755.         if (_dom_validate_name(qname) == false)
  756.                 return DOM_INVALID_CHARACTER_ERR;
  757.  
  758.         /* Validate qname */
  759.         err = _dom_namespace_validate_qname(qname, namespace);
  760.         if (err != DOM_NO_ERR) {
  761.                 return err;
  762.         }
  763.  
  764.         /* Divide QName into prefix/localname pair */
  765.         err = _dom_namespace_split_qname(qname, &prefix, &localname);
  766.         if (err != DOM_NO_ERR) {
  767.                 return err;
  768.         }
  769.  
  770.         /* Attempt to create attribute */
  771.         err = _dom_attr_create(doc, localname, namespace, prefix, true, result);
  772.  
  773.         /* Tidy up */
  774.         if (localname != NULL) {
  775.                 dom_string_unref(localname);
  776.         }
  777.  
  778.         if (prefix != NULL) {
  779.                 dom_string_unref(prefix);
  780.         }
  781.  
  782.         return err;
  783. }
  784.  
  785. /**
  786.  * Retrieve a list of all elements with a given local name and namespace URI
  787.  *
  788.  * \param doc        The document to search in
  789.  * \param namespace  The namespace URI
  790.  * \param localname  The local name
  791.  * \param result     Pointer to location to receive result
  792.  * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
  793.  *
  794.  * The returned list will have its reference count increased. It is
  795.  * the responsibility of the caller to unref the list once it has
  796.  * finished with it.
  797.  */
  798. dom_exception _dom_document_get_elements_by_tag_name_ns(
  799.                 dom_document *doc, dom_string *namespace,
  800.                 dom_string *localname, dom_nodelist **result)
  801. {
  802.         return _dom_document_get_nodelist(doc, DOM_NODELIST_BY_NAMESPACE,
  803.                         (dom_node_internal *) doc, NULL, namespace, localname,
  804.                         result);
  805. }
  806.  
  807. /**
  808.  * Retrieve the element that matches the specified ID
  809.  *
  810.  * \param doc     The document to search in
  811.  * \param id      The ID to search for
  812.  * \param result  Pointer to location to receive result
  813.  * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
  814.  *
  815.  * The returned node will have its reference count increased. It is
  816.  * the responsibility of the caller to unref the node once it has
  817.  * finished with it.
  818.  */
  819. dom_exception _dom_document_get_element_by_id(dom_document *doc,
  820.                 dom_string *id, dom_element **result)
  821. {
  822.         dom_node_internal *root;
  823.         dom_exception err;
  824.  
  825.         *result = NULL;
  826.  
  827.         err = dom_document_get_document_element(doc, (void *) &root);
  828.         if (err != DOM_NO_ERR)
  829.                 return err;
  830.  
  831.         err = _dom_find_element_by_id(root, id, result);
  832.         dom_node_unref(root);
  833.  
  834.         return err;
  835. }
  836.  
  837. /**
  838.  * Retrieve the input encoding of the document
  839.  *
  840.  * \param doc     The document to query
  841.  * \param result  Pointer to location to receive result
  842.  * \return DOM_NOT_SUPPORTED_ERR, we don't support this API now.
  843.  *
  844.  * The returned string will have its reference count increased. It is
  845.  * the responsibility of the caller to unref the string once it has
  846.  * finished with it.
  847.  */
  848. dom_exception _dom_document_get_input_encoding(dom_document *doc,
  849.                 dom_string **result)
  850. {
  851.         UNUSED(doc);
  852.         UNUSED(result);
  853.  
  854.         return DOM_NOT_SUPPORTED_ERR;
  855. }
  856.  
  857. /**
  858.  * Retrieve the XML encoding of the document
  859.  *
  860.  * \param doc     The document to query
  861.  * \param result  Pointer to location to receive result
  862.  * \return DOM_NOT_SUPPORTED_ERR, we don't support this API now.
  863.  *
  864.  * The returned string will have its reference count increased. It is
  865.  * the responsibility of the caller to unref the string once it has
  866.  * finished with it.
  867.  */
  868. dom_exception _dom_document_get_xml_encoding(dom_document *doc,
  869.                 dom_string **result)
  870. {
  871.         UNUSED(doc);
  872.         UNUSED(result);
  873.  
  874.         return DOM_NOT_SUPPORTED_ERR;
  875. }
  876.  
  877. /**
  878.  * Retrieve the standalone status of the document
  879.  *
  880.  * \param doc     The document to query
  881.  * \param result  Pointer to location to receive result
  882.  * \return DOM_NOT_SUPPORTED_ERR, we don't support this API now.
  883.  */
  884. dom_exception _dom_document_get_xml_standalone(dom_document *doc,
  885.                 bool *result)
  886. {
  887.         UNUSED(doc);
  888.         UNUSED(result);
  889.  
  890.         return DOM_NOT_SUPPORTED_ERR;
  891. }
  892.  
  893. /**
  894.  * Set the standalone status of the document
  895.  *
  896.  * \param doc         The document to query
  897.  * \param standalone  Standalone status to use
  898.  * \return DOM_NO_ERR            on success,
  899.  *         DOM_NOT_SUPPORTED_ERR if the document does not support the "XML"
  900.  *                               feature.
  901.  *
  902.  * We don't support this API now, so the return value is always
  903.  * DOM_NOT_SUPPORTED_ERR.
  904.  */
  905. dom_exception _dom_document_set_xml_standalone(dom_document *doc,
  906.                 bool standalone)
  907. {
  908.         UNUSED(doc);
  909.         UNUSED(standalone);
  910.  
  911.         return DOM_NOT_SUPPORTED_ERR;
  912. }
  913.  
  914. /**
  915.  * Retrieve the XML version of the document
  916.  *
  917.  * \param doc     The document to query
  918.  * \param result  Pointer to location to receive result
  919.  * \return DOM_NO_ERR
  920.  *
  921.  * The returned string will have its reference count increased. It is
  922.  * the responsibility of the caller to unref the string once it has
  923.  * finished with it.
  924.  *
  925.  * We don't support this API now, so the return value is always
  926.  * DOM_NOT_SUPPORTED_ERR.
  927.  */
  928. dom_exception _dom_document_get_xml_version(dom_document *doc,
  929.                 dom_string **result)
  930. {
  931.         UNUSED(doc);
  932.         UNUSED(result);
  933.  
  934.         return DOM_NOT_SUPPORTED_ERR;
  935. }
  936.  
  937. /**
  938.  * Set the XML version of the document
  939.  *
  940.  * \param doc      The document to query
  941.  * \param version  XML version to use
  942.  * \return DOM_NO_ERR            on success,
  943.  *         DOM_NOT_SUPPORTED_ERR if the document does not support the "XML"
  944.  *                               feature.
  945.  *
  946.  * We don't support this API now, so the return value is always
  947.  * DOM_NOT_SUPPORTED_ERR.
  948.  */
  949. dom_exception _dom_document_set_xml_version(dom_document *doc,
  950.                 dom_string *version)
  951. {
  952.         UNUSED(doc);
  953.         UNUSED(version);
  954.  
  955.         return DOM_NOT_SUPPORTED_ERR;
  956. }
  957.  
  958. /**
  959.  * Retrieve the error checking mode of the document
  960.  *
  961.  * \param doc     The document to query
  962.  * \param result  Pointer to location to receive result
  963.  * \return DOM_NOT_SUPPORTED_ERR, we don't support this API now.
  964.  */
  965. dom_exception _dom_document_get_strict_error_checking(
  966.                 dom_document *doc, bool *result)
  967. {
  968.         UNUSED(doc);
  969.         UNUSED(result);
  970.  
  971.         return DOM_NOT_SUPPORTED_ERR;
  972. }
  973.  
  974. /**
  975.  * Set the error checking mode of the document
  976.  *
  977.  * \param doc     The document to query
  978.  * \param strict  Whether to use strict error checking
  979.  * \return DOM_NOT_SUPPORTED_ERR, we don't support this API now.
  980.  */
  981. dom_exception _dom_document_set_strict_error_checking(
  982.                 dom_document *doc, bool strict)
  983. {
  984.         UNUSED(doc);
  985.         UNUSED(strict);
  986.  
  987.         return DOM_NOT_SUPPORTED_ERR;
  988. }
  989.  
  990. /**
  991.  * Retrieve the URI of the document
  992.  *
  993.  * \param doc     The document to query
  994.  * \param result  Pointer to location to receive result
  995.  * \return DOM_NO_ERR.
  996.  *
  997.  * The returned string will have its reference count increased. It is
  998.  * the responsibility of the caller to unref the string once it has
  999.  * finished with it.
  1000.  */
  1001. dom_exception _dom_document_get_uri(dom_document *doc,
  1002.                 dom_string **result)
  1003. {
  1004.         *result = dom_string_ref(doc->uri);
  1005.  
  1006.         return DOM_NO_ERR;
  1007. }
  1008.  
  1009. /**
  1010.  * Set the URI of the document
  1011.  *
  1012.  * \param doc  The document to query
  1013.  * \param uri  The URI to use
  1014.  * \return DOM_NO_ERR.
  1015.  *
  1016.  * The returned string will have its reference count increased. It is
  1017.  * the responsibility of the caller to unref the string once it has
  1018.  * finished with it.
  1019.  */
  1020. dom_exception _dom_document_set_uri(dom_document *doc,
  1021.                 dom_string *uri)
  1022. {
  1023.         dom_string_unref(doc->uri);
  1024.  
  1025.         doc->uri = dom_string_ref(uri);
  1026.  
  1027.         return DOM_NO_ERR;
  1028. }
  1029.  
  1030. /**
  1031.  * Attempt to adopt a node from another document into this document
  1032.  *
  1033.  * \param doc     The document to adopt into
  1034.  * \param node    The node to adopt
  1035.  * \param result  Pointer to location to receive adopted node
  1036.  * \return DOM_NO_ERR                      on success,
  1037.  *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::node is readonly,
  1038.  *         DOM_NOT_SUPPORTED_ERR           if ::node is of type Document or
  1039.  *                                         DocumentType
  1040.  *
  1041.  * The returned node will have its reference count increased. It is
  1042.  * the responsibility of the caller to unref the node once it has
  1043.  * finished with it.
  1044.  *
  1045.  * @note: The spec said adoptNode may be light weight than the importNode
  1046.  *        because the former need no Node creation. But in our implementation
  1047.  *        this can't be ensured. Both adoptNode and importNode create new
  1048.  *        nodes using the importing/adopting document's resource manager. So,
  1049.  *        generally, the adoptNode and importNode call the same function
  1050.  *        dom_document_dup_node.
  1051.  */
  1052. dom_exception _dom_document_adopt_node(dom_document *doc,
  1053.                 dom_node *node, dom_node **result)
  1054. {
  1055.         dom_node_internal *n = (dom_node_internal *) node;
  1056.         dom_exception err;
  1057.         dom_node_internal *parent;
  1058.         dom_node_internal *tmp;
  1059.        
  1060.         *result = NULL;
  1061.  
  1062.         if (n->type == DOM_DOCUMENT_NODE ||
  1063.                         n->type == DOM_DOCUMENT_TYPE_NODE) {
  1064.                 return DOM_NOT_SUPPORTED_ERR;          
  1065.         }
  1066.  
  1067.         if (n->type == DOM_ENTITY_NODE ||
  1068.                         n->type == DOM_NOTATION_NODE ||
  1069.                         n->type == DOM_PROCESSING_INSTRUCTION_NODE ||
  1070.                         n->type == DOM_TEXT_NODE ||
  1071.                         n->type == DOM_CDATA_SECTION_NODE ||
  1072.                         n->type == DOM_COMMENT_NODE) {
  1073.                 *result = NULL;
  1074.                 return DOM_NO_ERR;
  1075.         }
  1076.  
  1077.         /* Support XML when necessary */
  1078.         if (n->type == DOM_ENTITY_REFERENCE_NODE) {
  1079.                 return DOM_NOT_SUPPORTED_ERR;
  1080.         }
  1081.  
  1082.         err = dom_document_dup_node(doc, node, true, result, DOM_NODE_ADOPTED);
  1083.         if (err != DOM_NO_ERR) {
  1084.                 *result = NULL;
  1085.                 return err;
  1086.         }
  1087.  
  1088.         parent = n->parent;
  1089.         if (parent != NULL) {
  1090.                 err = dom_node_remove_child(parent, node, (void *) &tmp);
  1091.                 if (err != DOM_NO_ERR) {
  1092.                         dom_node_unref(*result);
  1093.                         *result = NULL;
  1094.                         return err;
  1095.                 }
  1096.                 dom_node_unref(tmp);
  1097.         }
  1098.  
  1099.         return DOM_NO_ERR;
  1100. }
  1101.  
  1102. /**
  1103.  * Retrieve the DOM configuration associated with a document
  1104.  *
  1105.  * \param doc     The document to query
  1106.  * \param result  Pointer to location to receive result
  1107.  * \return DOM_NOT_SUPPORTED_ERR, we don't support this API now.
  1108.  *
  1109.  * The returned object will have its reference count increased. It is
  1110.  * the responsibility of the caller to unref the object once it has
  1111.  * finished with it.
  1112.  */
  1113. dom_exception _dom_document_get_dom_config(dom_document *doc,
  1114.                 struct dom_configuration **result)
  1115. {
  1116.         UNUSED(doc);
  1117.         UNUSED(result);
  1118.  
  1119.         return DOM_NOT_SUPPORTED_ERR;
  1120. }
  1121.  
  1122. /**
  1123.  * Normalize a document
  1124.  *
  1125.  * \param doc  The document to normalize
  1126.  * \return DOM_NOT_SUPPORTED_ERR, we don't support this API now.
  1127.  */
  1128. dom_exception _dom_document_normalize(dom_document *doc)
  1129. {
  1130.         UNUSED(doc);
  1131.  
  1132.         return DOM_NOT_SUPPORTED_ERR;
  1133. }
  1134.  
  1135. /**
  1136.  * Rename a node in a document
  1137.  *
  1138.  * \param doc        The document containing the node
  1139.  * \param node       The node to rename
  1140.  * \param namespace  The new namespace for the node
  1141.  * \param qname      The new qualified name for the node
  1142.  * \param result     Pointer to location to receive renamed node
  1143.  * \return DOM_NO_ERR                on success,
  1144.  *         DOM_INVALID_CHARACTER_ERR if ::tag_name is invalid,
  1145.  *         DOM_WRONG_DOCUMENT_ERR    if ::node was created in a different
  1146.  *                                   document
  1147.  *         DOM_NAMESPACE_ERR         if ::qname is malformed, or it has a
  1148.  *                                   prefix and ::namespace is NULL, or
  1149.  *                                   ::qname has a prefix "xml" and
  1150.  *                                   ::namespace is not
  1151.  *                                   "http://www.w3.org/XML/1998/namespace",
  1152.  *                                   or ::qname has a prefix "xmlns" and
  1153.  *                                   ::namespace is not
  1154.  *                                   "http://www.w3.org/2000/xmlns", or
  1155.  *                                   ::namespace is
  1156.  *                                   "http://www.w3.org/2000/xmlns" and
  1157.  *                                   ::qname is not (or is not prefixed by)
  1158.  *                                   "xmlns",
  1159.  *         DOM_NOT_SUPPORTED_ERR     if ::doc does not support the "XML"
  1160.  *                                   feature.
  1161.  *
  1162.  * The returned node will have its reference count increased. It is
  1163.  * the responsibility of the caller to unref the node once it has
  1164.  * finished with it.
  1165.  *
  1166.  * We don't support this API now, so the return value is always
  1167.  * DOM_NOT_SUPPORTED_ERR.
  1168.  */
  1169. dom_exception _dom_document_rename_node(dom_document *doc,
  1170.                 dom_node *node,
  1171.                 dom_string *namespace, dom_string *qname,
  1172.                 dom_node **result)
  1173. {
  1174.         UNUSED(doc);
  1175.         UNUSED(node);
  1176.         UNUSED(namespace);
  1177.         UNUSED(qname);
  1178.         UNUSED(result);
  1179.  
  1180.         return DOM_NOT_SUPPORTED_ERR;
  1181. }
  1182.  
  1183. dom_exception _dom_document_get_text_content(dom_node_internal *node,
  1184.                                              dom_string **result)
  1185. {
  1186.         UNUSED(node);
  1187.        
  1188.         *result = NULL;
  1189.        
  1190.         return DOM_NO_ERR;
  1191. }
  1192.  
  1193. dom_exception _dom_document_set_text_content(dom_node_internal *node,
  1194.                                              dom_string *content)
  1195. {
  1196.         UNUSED(node);
  1197.         UNUSED(content);
  1198.        
  1199.         return DOM_NO_ERR;
  1200. }
  1201.  
  1202. /*-----------------------------------------------------------------------*/
  1203.  
  1204. /* Overload protected virtual functions */
  1205.  
  1206. /* The virtual destroy function of this class */
  1207. void _dom_document_destroy(dom_node_internal *node)
  1208. {
  1209.         dom_document *doc = (dom_document *) node;
  1210.  
  1211.         if (_dom_document_finalise(doc) == true) {
  1212.                 free(doc);
  1213.         }
  1214. }
  1215.  
  1216. /* The copy constructor function of this class */
  1217. dom_exception _dom_document_copy(dom_node_internal *old,
  1218.                 dom_node_internal **copy)
  1219. {
  1220.         UNUSED(old);
  1221.         UNUSED(copy);
  1222.  
  1223.         return DOM_NOT_SUPPORTED_ERR;
  1224. }
  1225.  
  1226.  
  1227. /* ----------------------------------------------------------------------- */
  1228.  
  1229. /* Helper functions */
  1230.  
  1231. /**
  1232.  * Get a nodelist, creating one if necessary
  1233.  *
  1234.  * \param doc        The document to get a nodelist for
  1235.  * \param type       The type of the NodeList
  1236.  * \param root       Root node of subtree that list applies to
  1237.  * \param tagname    Name of nodes in list (or NULL)
  1238.  * \param namespace  Namespace part of nodes in list (or NULL)
  1239.  * \param localname  Local part of nodes in list (or NULL)
  1240.  * \param list       Pointer to location to receive list
  1241.  * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion
  1242.  *
  1243.  * The returned list will have its reference count increased. It is
  1244.  * the responsibility of the caller to unref the list once it has
  1245.  * finished with it.
  1246.  */
  1247. dom_exception _dom_document_get_nodelist(dom_document *doc,
  1248.                 nodelist_type type, dom_node_internal *root,
  1249.                 dom_string *tagname, dom_string *namespace,
  1250.                 dom_string *localname, dom_nodelist **list)
  1251. {
  1252.         struct dom_doc_nl *l;
  1253.         dom_exception err;
  1254.  
  1255.         for (l = doc->nodelists; l; l = l->next) {
  1256.                 if (_dom_nodelist_match(l->list, type, root, tagname,
  1257.                                 namespace, localname))
  1258.                         break;
  1259.         }
  1260.  
  1261.         if (l != NULL) {
  1262.                 /* Found an existing list, so use it */
  1263.                 dom_nodelist_ref(l->list);
  1264.         } else {
  1265.                 /* No existing list */
  1266.  
  1267.                 /* Create active list entry */
  1268.                 l = malloc(sizeof(struct dom_doc_nl));
  1269.                 if (l == NULL)
  1270.                         return DOM_NO_MEM_ERR;
  1271.  
  1272.                 /* Create nodelist */
  1273.                 err = _dom_nodelist_create(doc, type, root, tagname, namespace,
  1274.                                 localname, &l->list);
  1275.                 if (err != DOM_NO_ERR) {
  1276.                         free(l);
  1277.                         return err;
  1278.                 }
  1279.  
  1280.                 /* Add to document's list of active nodelists */
  1281.                 l->prev = NULL;
  1282.                 l->next = doc->nodelists;
  1283.                 if (doc->nodelists)
  1284.                         doc->nodelists->prev = l;
  1285.                 doc->nodelists = l;
  1286.         }
  1287.  
  1288.         /* Note: the document does not claim a reference on the nodelist
  1289.          * If it did, the nodelist's reference count would never reach zero,
  1290.          * and the list would remain indefinitely. This is not a problem as
  1291.          * the list notifies the document of its destruction via
  1292.          * _dom_document_remove_nodelist. */
  1293.  
  1294.         *list = l->list;
  1295.  
  1296.         return DOM_NO_ERR;
  1297. }
  1298.  
  1299. /**
  1300.  * Remove a nodelist from a document
  1301.  *
  1302.  * \param doc   The document to remove the list from
  1303.  * \param list  The list to remove
  1304.  */
  1305. void _dom_document_remove_nodelist(dom_document *doc,
  1306.                 dom_nodelist *list)
  1307. {
  1308.         struct dom_doc_nl *l;
  1309.  
  1310.         for (l = doc->nodelists; l; l = l->next) {
  1311.                 if (l->list == list)
  1312.                         break;
  1313.         }
  1314.  
  1315.         if (l == NULL) {
  1316.                 /* This should never happen; we should probably abort here */
  1317.                 return;
  1318.         }
  1319.  
  1320.         /* Remove from list */
  1321.         if (l->prev != NULL)
  1322.                 l->prev->next = l->next;
  1323.         else
  1324.                 doc->nodelists = l->next;
  1325.  
  1326.         if (l->next != NULL)
  1327.                 l->next->prev = l->prev;
  1328.  
  1329.         /* And free item */
  1330.         free(l);
  1331. }
  1332.  
  1333. /**
  1334.  * Find element with certain ID in the subtree rooted at root
  1335.  *
  1336.  * \param root    The root element from where we start
  1337.  * \param id      The ID of the target element
  1338.  * \param result  The result element
  1339.  * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
  1340.  */
  1341. dom_exception _dom_find_element_by_id(dom_node_internal *root,
  1342.                 dom_string *id, dom_element **result)
  1343. {
  1344.         dom_node_internal *node = root;
  1345.  
  1346.         *result = NULL;
  1347.  
  1348.         while (node != NULL) {
  1349.                 if (node->type == DOM_ELEMENT_NODE) {
  1350.                         dom_string *real_id;
  1351.  
  1352.                         _dom_element_get_id((dom_element *) node, &real_id);
  1353.                         if (real_id != NULL) {
  1354.                                 if (dom_string_isequal(real_id, id)) {
  1355.                                         dom_string_unref(real_id);
  1356.                                         *result = (dom_element *) node;
  1357.                                         return DOM_NO_ERR;
  1358.                                 }
  1359.  
  1360.                                 dom_string_unref(real_id);
  1361.                         }
  1362.                 }
  1363.  
  1364.                 if (node->first_child != NULL) {
  1365.                         /* Has children */
  1366.                         node = node->first_child;
  1367.                 } else if (node->next != NULL) {
  1368.                         /* No children, but has siblings */
  1369.                         node = node->next;
  1370.                 } else {
  1371.                         /* No children or siblings.
  1372.                          * Find first unvisited relation. */
  1373.                         dom_node_internal *parent = node->parent;
  1374.  
  1375.                         while (parent != root &&
  1376.                                         node == parent->last_child) {
  1377.                                 node = parent;
  1378.                                 parent = parent->parent;
  1379.                         }
  1380.  
  1381.                         node = node->next;
  1382.                 }
  1383.         }
  1384.  
  1385.         return DOM_NO_ERR;
  1386. }
  1387.  
  1388. /**
  1389.  * Duplicate a Node
  1390.  *
  1391.  * \param doc     The documen
  1392.  * \param node    The node to duplicate
  1393.  * \param deep    Whether to make a deep copy
  1394.  * \param result  The returned node
  1395.  * \param opt     Whether this is adopt or import operation
  1396.  * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
  1397.  */
  1398. dom_exception dom_document_dup_node(dom_document *doc, dom_node *node,
  1399.                 bool deep, dom_node **result, dom_node_operation opt)
  1400. {
  1401.         dom_node_internal *n = (dom_node_internal *) node;
  1402.         dom_node_internal *ret;
  1403.         dom_exception err;
  1404.         dom_node_internal *child, *r;
  1405.         dom_user_data *ud;
  1406.  
  1407.         if (opt == DOM_NODE_ADOPTED && _dom_node_readonly(n))
  1408.                 return DOM_NO_MODIFICATION_ALLOWED_ERR;
  1409.        
  1410.         if (n->type == DOM_DOCUMENT_NODE ||
  1411.                         n->type == DOM_DOCUMENT_TYPE_NODE)
  1412.                 return DOM_NOT_SUPPORTED_ERR;
  1413.  
  1414.         err = dom_node_copy(node, &ret);
  1415.         if (err != DOM_NO_ERR)
  1416.                 return err;
  1417.  
  1418.         if (n->type == DOM_ATTRIBUTE_NODE) {
  1419.                 _dom_attr_set_specified((dom_attr *) node, true);
  1420.                 deep = true;
  1421.         }
  1422.  
  1423.         if (n->type == DOM_ENTITY_REFERENCE_NODE) {
  1424.                 deep = false;
  1425.         }
  1426.  
  1427.         if (n->type == DOM_ELEMENT_NODE) {
  1428.                 /* Specified attributes are copyied but not default attributes,
  1429.                  * if the document object hold all the default attributes, we
  1430.                  * have nothing to do here */
  1431.         }
  1432.  
  1433.         if (opt == DOM_NODE_ADOPTED && (n->type == DOM_ENTITY_NODE ||
  1434.                         n->type == DOM_NOTATION_NODE)) {
  1435.                 /* We did not support XML now */
  1436.                 return DOM_NOT_SUPPORTED_ERR;
  1437.         }
  1438.  
  1439.         if (deep == true) {
  1440.                 child = ((dom_node_internal *) node)->first_child;
  1441.                 while (child != NULL) {
  1442.                         err = dom_document_import_node(doc, child, deep,
  1443.                                         (void *) &r);
  1444.                         if (err != DOM_NO_ERR) {
  1445.                                 dom_node_unref(ret);
  1446.                                 return err;
  1447.                         }
  1448.  
  1449.                         err = dom_node_append_child(ret, r, (void *) &r);
  1450.                         if (err != DOM_NO_ERR) {
  1451.                                 dom_node_unref(ret);
  1452.                                 dom_node_unref(r);
  1453.                                 return err;
  1454.                         }
  1455.                         dom_node_unref(r);
  1456.  
  1457.                         child = child->next;
  1458.                 }
  1459.         }
  1460.  
  1461.         /* Call the dom_user_data_handlers */
  1462.         ud = n->user_data;
  1463.         while (ud != NULL) {
  1464.                 if (ud->handler != NULL) {
  1465.                         ud->handler(opt, ud->key, ud->data, node,
  1466.                                         (dom_node *) ret);
  1467.                 }
  1468.                 ud = ud->next;
  1469.         }
  1470.  
  1471.         *result = (dom_node *) ret;
  1472.  
  1473.         return DOM_NO_ERR;
  1474. }
  1475.  
  1476. /**
  1477.  * Try to destroy the document.
  1478.  *
  1479.  * \param doc  The instance of Document
  1480.  *
  1481.  * Delete the document if:
  1482.  * 1. The refcnt reach zero
  1483.  * 2. The pending list is empty
  1484.  *
  1485.  * else, do nothing.
  1486.  */
  1487. void _dom_document_try_destroy(dom_document *doc)
  1488. {
  1489.         if (doc->base.base.refcnt != 0 || doc->base.parent != NULL)
  1490.                 return;
  1491.  
  1492.         _dom_document_destroy((dom_node_internal *) doc);
  1493. }
  1494.  
  1495. /**
  1496.  * Set the ID attribute name of this document
  1497.  *
  1498.  * \param doc   The document object
  1499.  * \param name  The ID name of the elements in this document
  1500.  */
  1501. void _dom_document_set_id_name(dom_document *doc, dom_string *name)
  1502. {
  1503.         if (doc->id_name != NULL)
  1504.                 dom_string_unref(doc->id_name);
  1505.         doc->id_name = dom_string_ref(name);
  1506. }
  1507.  
  1508. /*-----------------------------------------------------------------------*/
  1509. /* Semi-internal API extensions for NetSurf */
  1510.  
  1511. dom_exception _dom_document_get_quirks_mode(dom_document *doc,
  1512.                 dom_document_quirks_mode *result)
  1513. {
  1514.         *result = doc->quirks;
  1515.         return DOM_NO_ERR;
  1516. }
  1517.  
  1518. dom_exception _dom_document_set_quirks_mode(dom_document *doc,
  1519.                 dom_document_quirks_mode quirks)
  1520. {
  1521.         doc->quirks = quirks;
  1522.         return DOM_NO_ERR;
  1523. }
  1524.