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 <stdbool.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14
15 #include <dom/core/attr.h>
16 #include <dom/core/text.h>
17 #include <dom/core/document.h>
18 #include <dom/core/namednodemap.h>
19 #include <dom/core/nodelist.h>
20 #include <dom/core/implementation.h>
21 #include <dom/core/document_type.h>
22 #include <dom/events/events.h>
23
24 #include "core/string.h"
25 #include "core/namednodemap.h"
26 #include "core/attr.h"
27 #include "core/cdatasection.h"
28 #include "core/comment.h"
29 #include "core/document.h"
30 #include "core/document_type.h"
31 #include "core/doc_fragment.h"
32 #include "core/element.h"
33 #include "core/entity_ref.h"
34 #include "core/node.h"
35 #include "core/pi.h"
36 #include "core/text.h"
37 #include "utils/utils.h"
38 #include "utils/validate.h"
39 #include "events/mutation_event.h"
40
41 static bool _dom_node_permitted_child(const dom_node_internal *parent,
42 const dom_node_internal *child);
43 static inline dom_exception _dom_node_attach(dom_node_internal *node,
44 dom_node_internal *parent,
45 dom_node_internal *previous,
46 dom_node_internal *next);
47 static inline void _dom_node_detach(dom_node_internal *node);
48 static inline dom_exception _dom_node_attach_range(dom_node_internal *first,
49 dom_node_internal *last,
50 dom_node_internal *parent,
51 dom_node_internal *previous,
52 dom_node_internal *next);
53 static inline dom_exception _dom_node_detach_range(dom_node_internal *first,
54 dom_node_internal *last);
55 static inline void _dom_node_replace(dom_node_internal *old,
56 dom_node_internal *replacement);
57
58 static struct dom_node_vtable node_vtable = {
59 {
60 DOM_NODE_EVENT_TARGET_VTABLE
61 },
62 DOM_NODE_VTABLE
63 };
64
65 static struct dom_node_protect_vtable node_protect_vtable = {
66 DOM_NODE_PROTECT_VTABLE
67 };
68
69
70
71 /*----------------------------------------------------------------------*/
72
73 /* The constructor and destructor of this object */
74
75 /* Create a DOM node and compose the vtable */
_dom_node_create(void)76 dom_node_internal * _dom_node_create(void)
77 {
78 dom_node_internal *node = malloc(sizeof(struct dom_node_internal));
79 if (node == NULL)
80 return NULL;
81
82 node->base.vtable = &node_vtable;
83 node->vtable = &node_protect_vtable;
84 return node;
85 }
86
87 /**
88 * Destroy a DOM node
89 *
90 * \param node The node to destroy
91 *
92 * ::node's parent link must be NULL and its reference count must be 0.
93 *
94 * ::node will be freed.
95 *
96 * This function should only be called from dom_node_unref or type-specific
97 * destructors (for destroying child nodes). Anything else should not
98 * be attempting to destroy nodes -- they should simply be unreferencing
99 * them (so destruction will occur at the appropriate time).
100 */
_dom_node_destroy(struct dom_node_internal * node)101 void _dom_node_destroy(struct dom_node_internal *node)
102 {
103 struct dom_document *owner = node->owner;
104 bool null_owner_permitted = (node->type == DOM_DOCUMENT_NODE ||
105 node->type == DOM_DOCUMENT_TYPE_NODE);
106
107 assert(null_owner_permitted || owner != NULL);
108
109 if (!null_owner_permitted) {
110 /* Claim a reference upon the owning document during
111 * destruction to ensure that the document doesn't get
112 * destroyed before its contents. */
113 dom_node_ref(owner);
114 }
115
116 /* Finalise this node, this should also destroy all the child nodes. */
117 _dom_node_finalise(node);
118
119 if (!null_owner_permitted) {
120 /* Release the reference we claimed on the document. If this
121 * is the last reference held on the document and the list
122 * of nodes pending deletion is empty, then the document will
123 * be destroyed. */
124 dom_node_unref(owner);
125 }
126
127 /* Release our memory */
128 free(node);
129 }
130
131 /**
132 * Initialise a DOM node
133 *
134 * \param node The node to initialise
135 * \param doc The document which owns the node
136 * \param type The node type required
137 * \param name The node (local) name, or NULL
138 * \param value The node value, or NULL
139 * \param namespace Namespace URI to use for node, or NULL
140 * \param prefix Namespace prefix to use for node, or NULL
141 * \return DOM_NO_ERR on success.
142 *
143 * ::name, ::value, ::namespace, and ::prefix will have their reference
144 * counts increased.
145 */
_dom_node_initialise(dom_node_internal * node,struct dom_document * doc,dom_node_type type,dom_string * name,dom_string * value,dom_string * namespace,dom_string * prefix)146 dom_exception _dom_node_initialise(dom_node_internal *node,
147 struct dom_document *doc, dom_node_type type,
148 dom_string *name, dom_string *value,
149 dom_string *namespace, dom_string *prefix)
150 {
151 node->owner = doc;
152
153 if (name != NULL)
154 node->name = dom_string_ref(name);
155 else
156 node->name = NULL;
157
158 if (value != NULL)
159 node->value = dom_string_ref(value);
160 else
161 node->value = NULL;
162
163 node->type = type;
164
165 node->parent = NULL;
166 node->first_child = NULL;
167 node->last_child = NULL;
168 node->previous = NULL;
169 node->next = NULL;
170
171 /* Note: nodes do not reference the document to which they belong,
172 * as this would result in the document never being destroyed once
173 * the client has finished with it. The document will be aware of
174 * any nodes that it owns through 2 mechanisms:
175 *
176 * either a) Membership of the document tree
177 * or b) Membership of the list of nodes pending deletion
178 *
179 * It is not possible for any given node to be a member of both
180 * data structures at the same time.
181 *
182 * The document will not be destroyed until both of these
183 * structures are empty. It will forcibly attempt to empty
184 * the document tree on document destruction. Any still-referenced
185 * nodes at that time will be added to the list of nodes pending
186 * deletion. This list will not be forcibly emptied, as it contains
187 * those nodes (and their sub-trees) in use by client code.
188 */
189
190 if (namespace != NULL)
191 node->namespace = dom_string_ref(namespace);
192 else
193 node->namespace = NULL;
194
195 if (prefix != NULL)
196 node->prefix = dom_string_ref(prefix);
197 else
198 node->prefix = NULL;
199
200 node->user_data = NULL;
201
202 node->base.refcnt = 1;
203
204 list_init(&node->pending_list);
205 if (node->type != DOM_DOCUMENT_NODE) {
206 /* A Node should be in the pending list when it is created */
207 dom_node_mark_pending(node);
208 }
209
210 return _dom_event_target_internal_initialise(&node->eti);
211 }
212
213 /**
214 * Finalise a DOM node
215 *
216 * \param node The node to finalise
217 *
218 * The contents of ::node will be cleaned up. ::node will not be freed.
219 * All children of ::node should have been removed prior to finalisation.
220 */
_dom_node_finalise(dom_node_internal * node)221 void _dom_node_finalise(dom_node_internal *node)
222 {
223 struct dom_user_data *u, *v;
224 struct dom_node_internal *p;
225 struct dom_node_internal *n = NULL;
226
227 /* Destroy user data */
228 for (u = node->user_data; u != NULL; u = v) {
229 v = u->next;
230
231 if (u->handler != NULL)
232 u->handler(DOM_NODE_DELETED, u->key, u->data,
233 NULL, NULL);
234
235 dom_string_unref(u->key);
236 free(u);
237 }
238 node->user_data = NULL;
239
240 if (node->prefix != NULL) {
241 dom_string_unref(node->prefix);
242 node->prefix = NULL;
243 }
244
245 if (node->namespace != NULL) {
246 dom_string_unref(node->namespace);
247 node->namespace = NULL;
248 }
249
250 /* Destroy all the child nodes of this node */
251 p = node->first_child;
252 while (p != NULL) {
253 n = p->next;
254 p->parent = NULL;
255 dom_node_try_destroy(p);
256 p = n;
257 }
258
259 /* Paranoia */
260 node->next = NULL;
261 node->previous = NULL;
262 node->last_child = NULL;
263 node->first_child = NULL;
264 node->parent = NULL;
265
266 if (node->value != NULL) {
267 dom_string_unref(node->value);
268 node->value = NULL;
269 }
270
271 if (node->name != NULL) {
272 dom_string_unref(node->name);
273 node->name = NULL;
274 }
275
276 /* If the node has no owner document, we need not to finalise its
277 * dom_event_target_internal structure.
278 */
279 if (node->owner != NULL)
280 _dom_event_target_internal_finalise(&node->eti);
281
282 /* Detach from the pending list, if we are in it,
283 * this part of code should always be the end of this function. */
284 if (node->pending_list.prev != &node->pending_list) {
285 assert (node->pending_list.next != &node->pending_list);
286 list_del(&node->pending_list);
287 if (node->owner != NULL && node->type != DOM_DOCUMENT_NODE) {
288 /* Deleting this node from the pending list may cause
289 * the list to be null and we should try to destroy
290 * the document. */
291 _dom_document_try_destroy(node->owner);
292 }
293 }
294 }
295
296
297 /* ---------------------------------------------------------------------*/
298
299 /* The public non-virtual function of this interface Node */
300
_dom_node_contains(struct dom_node_internal * node,struct dom_node_internal * other,bool * contains)301 dom_exception _dom_node_contains(struct dom_node_internal *node,
302 struct dom_node_internal *other,
303 bool *contains)
304 {
305 assert(node != NULL);
306 assert(other != NULL);
307 assert(contains != NULL);
308
309 if (node->owner != other->owner) {
310 *contains = false;
311 return DOM_NO_ERR;
312 }
313
314 while (other != NULL) {
315 if (other == node) {
316 *contains = true;
317 return DOM_NO_ERR;
318 }
319 other = other->parent;
320 }
321
322 *contains = false;
323 return DOM_NO_ERR;
324 }
325
326
327 /* ---------------------------------------------------------------------*/
328
329 /* The public virtual function of this interface Node */
330
331 /**
332 * Retrieve the name of a DOM node
333 *
334 * \param node The node to retrieve the name of
335 * \param result Pointer to location to receive node name
336 * \return DOM_NO_ERR.
337 *
338 * The returned string will have its reference count increased. It is
339 * the responsibility of the caller to unref the string once it has
340 * finished with it.
341 */
_dom_node_get_node_name(dom_node_internal * node,dom_string ** result)342 dom_exception _dom_node_get_node_name(dom_node_internal *node,
343 dom_string **result)
344 {
345 dom_string *node_name, *temp;
346 dom_exception err;
347
348 /* Document Node and DocumentType Node can have no owner */
349 assert(node->type == DOM_DOCUMENT_TYPE_NODE ||
350 node->type == DOM_DOCUMENT_NODE ||
351 node->owner != NULL);
352
353 assert(node->name != NULL);
354
355 /* If this node was created using a namespace-aware method and
356 * has a defined prefix, then nodeName is a QName comprised
357 * of prefix:name. */
358 if (node->prefix != NULL) {
359 dom_string *colon;
360
361 err = dom_string_create((const uint8_t *) ":", SLEN(":"),
362 &colon);
363 if (err != DOM_NO_ERR) {
364 return err;
365 }
366
367 /* Prefix + : */
368 err = dom_string_concat(node->prefix, colon, &temp);
369 if (err != DOM_NO_ERR) {
370 dom_string_unref(colon);
371 return err;
372 }
373
374 /* Finished with colon */
375 dom_string_unref(colon);
376
377 /* Prefix + : + Localname */
378 err = dom_string_concat(temp, node->name, &node_name);
379 if (err != DOM_NO_ERR) {
380 dom_string_unref(temp);
381 return err;
382 }
383
384 /* Finished with temp */
385 dom_string_unref(temp);
386 } else {
387 node_name = dom_string_ref(node->name);
388 }
389
390 *result = node_name;
391
392 return DOM_NO_ERR;
393 }
394
395 /**
396 * Retrieve the value of a DOM node
397 *
398 * \param node The node to retrieve the value of
399 * \param result Pointer to location to receive node value
400 * \return DOM_NO_ERR.
401 *
402 * The returned string will have its reference count increased. It is
403 * the responsibility of the caller to unref the string once it has
404 * finished with it.
405 *
406 * DOM3Core states that this can raise DOMSTRING_SIZE_ERR. It will not in
407 * this implementation; dom_strings are unbounded.
408 */
_dom_node_get_node_value(dom_node_internal * node,dom_string ** result)409 dom_exception _dom_node_get_node_value(dom_node_internal *node,
410 dom_string **result)
411 {
412 if (node->value != NULL)
413 dom_string_ref(node->value);
414
415 *result = node->value;
416
417 return DOM_NO_ERR;
418 }
419
420 /**
421 * Set the value of a DOM node
422 *
423 * \param node Node to set the value of
424 * \param value New value for node
425 * \return DOM_NO_ERR on success,
426 * DOM_NO_MODIFICATION_ALLOWED_ERR if the node is readonly and the
427 * value is not defined to be null.
428 *
429 * The new value will have its reference count increased, so the caller
430 * should unref it after the call (as the caller should have already claimed
431 * a reference on the string). The node's existing value will be unrefed.
432 */
_dom_node_set_node_value(dom_node_internal * node,dom_string * value)433 dom_exception _dom_node_set_node_value(dom_node_internal *node,
434 dom_string *value)
435 {
436 /* TODO
437 * Whether we should change this to a virtual function?
438 */
439 /* This is a NOP if the value is defined to be null. */
440 if (node->type == DOM_DOCUMENT_NODE ||
441 node->type == DOM_DOCUMENT_FRAGMENT_NODE ||
442 node->type == DOM_DOCUMENT_TYPE_NODE ||
443 node->type == DOM_ELEMENT_NODE ||
444 node->type == DOM_ENTITY_NODE ||
445 node->type == DOM_ENTITY_REFERENCE_NODE ||
446 node->type == DOM_NOTATION_NODE) {
447 return DOM_NO_ERR;
448 }
449
450 /* Ensure node is writable */
451 if (_dom_node_readonly(node))
452 return DOM_NO_MODIFICATION_ALLOWED_ERR;
453
454 /* If it's an attribute node, then delegate setting to
455 * the type-specific function */
456 if (node->type == DOM_ATTRIBUTE_NODE)
457 return dom_attr_set_value((struct dom_attr *) node, value);
458
459 if (node->value != NULL)
460 dom_string_unref(node->value);
461
462 if (value != NULL)
463 dom_string_ref(value);
464
465 node->value = value;
466
467 return DOM_NO_ERR;
468 }
469
470 /**
471 * Retrieve the type of a DOM node
472 *
473 * \param node The node to retrieve the type of
474 * \param result Pointer to location to receive node type
475 * \return DOM_NO_ERR.
476 */
_dom_node_get_node_type(dom_node_internal * node,dom_node_type * result)477 dom_exception _dom_node_get_node_type(dom_node_internal *node,
478 dom_node_type *result)
479 {
480 *result = node->type;
481
482 return DOM_NO_ERR;
483 }
484
485 /**
486 * Retrieve the parent of a DOM node
487 *
488 * \param node The node to retrieve the parent of
489 * \param result Pointer to location to receive node parent
490 * \return DOM_NO_ERR.
491 *
492 * The returned node will have its reference count increased. It is
493 * the responsibility of the caller to unref the node once it has
494 * finished with it.
495 */
_dom_node_get_parent_node(dom_node_internal * node,dom_node_internal ** result)496 dom_exception _dom_node_get_parent_node(dom_node_internal *node,
497 dom_node_internal **result)
498 {
499 /* Attr nodes have no parent */
500 if (node->type == DOM_ATTRIBUTE_NODE) {
501 *result = NULL;
502 return DOM_NO_ERR;
503 }
504
505 /* If there is a parent node, then increase its reference count */
506 if (node->parent != NULL)
507 dom_node_ref(node->parent);
508
509 *result = node->parent;
510
511 return DOM_NO_ERR;
512 }
513
514 /**
515 * Retrieve a list of children of a DOM node
516 *
517 * \param node The node to retrieve the children of
518 * \param result Pointer to location to receive child list
519 * \return DOM_NO_ERR.
520 *
521 * The returned NodeList will be referenced. It is the responsibility
522 * of the caller to unref the list once it has finished with it.
523 */
_dom_node_get_child_nodes(dom_node_internal * node,struct dom_nodelist ** result)524 dom_exception _dom_node_get_child_nodes(dom_node_internal *node,
525 struct dom_nodelist **result)
526 {
527 /* Can't do anything without an owning document.
528 * This is only a problem for DocumentType nodes
529 * which are not yet attached to a document.
530 * DocumentType nodes have no children, anyway. */
531 if (node->owner == NULL)
532 return DOM_NOT_SUPPORTED_ERR;
533
534 return _dom_document_get_nodelist(node->owner, DOM_NODELIST_CHILDREN,
535 node, NULL, NULL, NULL, result);
536 }
537
538 /**
539 * Retrieve the first child of a DOM node
540 *
541 * \param node The node to retrieve the first child of
542 * \param result Pointer to location to receive node's first child
543 * \return DOM_NO_ERR.
544 *
545 * The returned node will have its reference count increased. It is
546 * the responsibility of the caller to unref the node once it has
547 * finished with it.
548 */
_dom_node_get_first_child(dom_node_internal * node,dom_node_internal ** result)549 dom_exception _dom_node_get_first_child(dom_node_internal *node,
550 dom_node_internal **result)
551 {
552 /* If there is a first child, increase its reference count */
553 if (node->first_child != NULL)
554 dom_node_ref(node->first_child);
555
556 *result = node->first_child;
557
558 return DOM_NO_ERR;
559 }
560
561 /**
562 * Retrieve the last child of a DOM node
563 *
564 * \param node The node to retrieve the last child of
565 * \param result Pointer to location to receive node's last child
566 * \return DOM_NO_ERR.
567 *
568 * The returned node will have its reference count increased. It is
569 * the responsibility of the caller to unref the node once it has
570 * finished with it.
571 */
_dom_node_get_last_child(dom_node_internal * node,dom_node_internal ** result)572 dom_exception _dom_node_get_last_child(dom_node_internal *node,
573 dom_node_internal **result)
574 {
575 /* If there is a last child, increase its reference count */
576 if (node->last_child != NULL)
577 dom_node_ref(node->last_child);
578
579 *result = node->last_child;
580
581 return DOM_NO_ERR;
582 }
583
584 /**
585 * Retrieve the previous sibling of a DOM node
586 *
587 * \param node The node to retrieve the previous sibling of
588 * \param result Pointer to location to receive node's previous sibling
589 * \return DOM_NO_ERR.
590 *
591 * The returned node will have its reference count increased. It is
592 * the responsibility of the caller to unref the node once it has
593 * finished with it.
594 */
_dom_node_get_previous_sibling(dom_node_internal * node,dom_node_internal ** result)595 dom_exception _dom_node_get_previous_sibling(dom_node_internal *node,
596 dom_node_internal **result)
597 {
598 /* Attr nodes have no previous siblings */
599 if (node->type == DOM_ATTRIBUTE_NODE) {
600 *result = NULL;
601 return DOM_NO_ERR;
602 }
603
604 /* If there is a previous sibling, increase its reference count */
605 if (node->previous != NULL)
606 dom_node_ref(node->previous);
607
608 *result = node->previous;
609
610 return DOM_NO_ERR;
611 }
612
613 /**
614 * Retrieve the subsequent sibling of a DOM node
615 *
616 * \param node The node to retrieve the subsequent sibling of
617 * \param result Pointer to location to receive node's subsequent sibling
618 * \return DOM_NO_ERR.
619 *
620 * The returned node will have its reference count increased. It is
621 * the responsibility of the caller to unref the node once it has
622 * finished with it.
623 */
_dom_node_get_next_sibling(dom_node_internal * node,dom_node_internal ** result)624 dom_exception _dom_node_get_next_sibling(dom_node_internal *node,
625 dom_node_internal **result)
626 {
627 /* Attr nodes have no next siblings */
628 if (node->type == DOM_ATTRIBUTE_NODE) {
629 *result = NULL;
630 return DOM_NO_ERR;
631 }
632
633 /* If there is a subsequent sibling, increase its reference count */
634 if (node->next != NULL)
635 dom_node_ref(node->next);
636
637 *result = node->next;
638
639 return DOM_NO_ERR;
640 }
641
642 /**
643 * Retrieve a map of attributes associated with a DOM node
644 *
645 * \param node The node to retrieve the attributes of
646 * \param result Pointer to location to receive attribute map
647 * \return DOM_NO_ERR.
648 *
649 * The returned NamedNodeMap will be referenced. It is the responsibility
650 * of the caller to unref the map once it has finished with it.
651 *
652 * If ::node is not an Element, then NULL will be returned.
653 */
_dom_node_get_attributes(dom_node_internal * node,struct dom_namednodemap ** result)654 dom_exception _dom_node_get_attributes(dom_node_internal *node,
655 struct dom_namednodemap **result)
656 {
657 UNUSED(node);
658 *result = NULL;
659
660 return DOM_NO_ERR;
661 }
662
663 /**
664 * Retrieve the owning document of a DOM node
665 *
666 * \param node The node to retrieve the owner of
667 * \param result Pointer to location to receive node's owner
668 * \return DOM_NO_ERR.
669 *
670 * The returned node will have its reference count increased. It is
671 * the responsibility of the caller to unref the node once it has
672 * finished with it.
673 */
_dom_node_get_owner_document(dom_node_internal * node,struct dom_document ** result)674 dom_exception _dom_node_get_owner_document(dom_node_internal *node,
675 struct dom_document **result)
676 {
677 /* Document nodes have no owner, as far as clients are concerned
678 * In reality, they own themselves as this simplifies code elsewhere */
679 if (node->type == DOM_DOCUMENT_NODE) {
680 *result = NULL;
681
682 return DOM_NO_ERR;
683 }
684
685 /* If there is an owner, increase its reference count */
686 if (node->owner != NULL)
687 dom_node_ref(node->owner);
688
689 *result = node->owner;
690
691 return DOM_NO_ERR;
692 }
693
694 /**
695 * Insert a child into a node
696 *
697 * \param node Node to insert into
698 * \param new_child Node to insert
699 * \param ref_child Node to insert before, or NULL to insert as last child
700 * \param result Pointer to location to receive node being inserted
701 * \return DOM_NO_ERR on success,
702 * DOM_HIERARCHY_REQUEST_ERR if ::new_child's type is not
703 * permitted as a child of ::node,
704 * or ::new_child is an ancestor of
705 * ::node (or is ::node itself), or
706 * ::node is of type Document and a
707 * second DocumentType or Element is
708 * being inserted,
709 * DOM_WRONG_DOCUMENT_ERR if ::new_child was created from a
710 * different document than ::node,
711 * DOM_NO_MODIFICATION_ALLOWED_ERR if ::node is readonly, or
712 * ::new_child's parent is readonly,
713 * DOM_NOT_FOUND_ERR if ::ref_child is not a child of
714 * ::node.
715 *
716 * If ::new_child is a DocumentFragment, all of its children are inserted.
717 * If ::new_child is already in the tree, it is first removed.
718 *
719 * Attempting to insert a node before itself is a NOP.
720 *
721 * The returned node will have its reference count increased. It is
722 * the responsibility of the caller to unref the node once it has
723 * finished with it.
724 */
_dom_node_insert_before(dom_node_internal * node,dom_node_internal * new_child,dom_node_internal * ref_child,dom_node_internal ** result)725 dom_exception _dom_node_insert_before(dom_node_internal *node,
726 dom_node_internal *new_child, dom_node_internal *ref_child,
727 dom_node_internal **result)
728 {
729 dom_exception err;
730 dom_node_internal *n;
731
732 assert(node != NULL);
733
734 /* Ensure that new_child and node are owned by the same document */
735 if ((new_child->type == DOM_DOCUMENT_TYPE_NODE &&
736 new_child->owner != NULL &&
737 new_child->owner != node->owner) ||
738 (new_child->type != DOM_DOCUMENT_TYPE_NODE &&
739 new_child->owner != node->owner))
740 return DOM_WRONG_DOCUMENT_ERR;
741
742 /* Ensure node isn't read only */
743 if (_dom_node_readonly(node))
744 return DOM_NO_MODIFICATION_ALLOWED_ERR;
745
746 /* Ensure that ref_child (if any) is a child of node */
747 if (ref_child != NULL && ref_child->parent != node)
748 return DOM_NOT_FOUND_ERR;
749
750 /* Ensure that new_child is not an ancestor of node, nor node itself */
751 for (n = node; n != NULL; n = n->parent) {
752 if (n == new_child)
753 return DOM_HIERARCHY_REQUEST_ERR;
754 }
755
756 /* Ensure that new_child is permitted as a child of node */
757 if (new_child->type != DOM_DOCUMENT_FRAGMENT_NODE &&
758 !_dom_node_permitted_child(node, new_child))
759 return DOM_HIERARCHY_REQUEST_ERR;
760
761 /* Attempting to insert a node before itself is a NOP */
762 if (new_child == ref_child) {
763 dom_node_ref(new_child);
764 *result = new_child;
765
766 return DOM_NO_ERR;
767 }
768
769 /* If new_child is already in the tree and
770 * its parent isn't read only, remove it */
771 if (new_child->parent != NULL) {
772 if (_dom_node_readonly(new_child->parent))
773 return DOM_NO_MODIFICATION_ALLOWED_ERR;
774
775 _dom_node_detach(new_child);
776 }
777
778 /* When a Node is attached, it should be removed from the pending
779 * list */
780 dom_node_remove_pending(new_child);
781
782 /* If new_child is a DocumentFragment, insert its children.
783 * Otherwise, insert new_child */
784 if (new_child->type == DOM_DOCUMENT_FRAGMENT_NODE) {
785 /* Test the children of the docment fragment can be appended */
786 dom_node_internal *c = new_child->first_child;
787 for (; c != NULL; c = c->next)
788 if (!_dom_node_permitted_child(node, c))
789 return DOM_HIERARCHY_REQUEST_ERR;
790
791 if (new_child->first_child != NULL) {
792 err = _dom_node_attach_range(new_child->first_child,
793 new_child->last_child,
794 node,
795 ref_child == NULL ? node->last_child
796 : ref_child->previous,
797 ref_child == NULL ? NULL
798 : ref_child);
799 if (err != DOM_NO_ERR)
800 return err;
801
802 new_child->first_child = NULL;
803 new_child->last_child = NULL;
804 }
805 } else {
806 err = _dom_node_attach(new_child,
807 node,
808 ref_child == NULL ? node->last_child
809 : ref_child->previous,
810 ref_child == NULL ? NULL
811 : ref_child);
812 if (err != DOM_NO_ERR)
813 return err;
814
815 }
816
817 /* DocumentType nodes are created outside the Document so,
818 * if we're trying to attach a DocumentType node, then we
819 * also need to set its owner. */
820 if (node->type == DOM_DOCUMENT_NODE &&
821 new_child->type == DOM_DOCUMENT_TYPE_NODE) {
822 /* See long comment in _dom_node_initialise as to why
823 * we don't ref the document here */
824 new_child->owner = (struct dom_document *) node;
825 }
826
827 /** \todo Is it correct to return DocumentFragments? */
828
829 dom_node_ref(new_child);
830 *result = new_child;
831
832 return DOM_NO_ERR;
833 }
834
835 /**
836 * Replace a node's child with a new one
837 *
838 * \param node Node whose child to replace
839 * \param new_child Replacement node
840 * \param old_child Child to replace
841 * \param result Pointer to location to receive replaced node
842 * \return DOM_NO_ERR on success,
843 * DOM_HIERARCHY_REQUEST_ERR if ::new_child's type is not
844 * permitted as a child of ::node,
845 * or ::new_child is an ancestor of
846 * ::node (or is ::node itself), or
847 * ::node is of type Document and a
848 * second DocumentType or Element is
849 * being inserted,
850 * DOM_WRONG_DOCUMENT_ERR if ::new_child was created from a
851 * different document than ::node,
852 * DOM_NO_MODIFICATION_ALLOWED_ERR if ::node is readonly, or
853 * ::new_child's parent is readonly,
854 * DOM_NOT_FOUND_ERR if ::old_child is not a child of
855 * ::node,
856 * DOM_NOT_SUPPORTED_ERR if ::node is of type Document and
857 * ::new_child is of type
858 * DocumentType or Element.
859 *
860 * If ::new_child is a DocumentFragment, ::old_child is replaced by all of
861 * ::new_child's children.
862 * If ::new_child is already in the tree, it is first removed.
863 *
864 * The returned node will have its reference count increased. It is
865 * the responsibility of the caller to unref the node once it has
866 * finished with it.
867 */
_dom_node_replace_child(dom_node_internal * node,dom_node_internal * new_child,dom_node_internal * old_child,dom_node_internal ** result)868 dom_exception _dom_node_replace_child(dom_node_internal *node,
869 dom_node_internal *new_child, dom_node_internal *old_child,
870 dom_node_internal **result)
871 {
872 dom_node_internal *n;
873
874 /* We don't support replacement of DocumentType or root Elements */
875 if (node->type == DOM_DOCUMENT_NODE &&
876 (new_child->type == DOM_DOCUMENT_TYPE_NODE ||
877 new_child->type == DOM_ELEMENT_NODE))
878 return DOM_NOT_SUPPORTED_ERR;
879
880 /* Ensure that new_child and node are owned by the same document */
881 if (new_child->owner != node->owner)
882 return DOM_WRONG_DOCUMENT_ERR;
883
884 /* Ensure node isn't read only */
885 if (_dom_node_readonly(node))
886 return DOM_NO_MODIFICATION_ALLOWED_ERR;
887
888 /* Ensure that old_child is a child of node */
889 if (old_child->parent != node)
890 return DOM_NOT_FOUND_ERR;
891
892 /* Ensure that new_child is not an ancestor of node, nor node itself */
893 for (n = node; n != NULL; n = n->parent) {
894 if (n == new_child)
895 return DOM_HIERARCHY_REQUEST_ERR;
896 }
897
898 /* Ensure that new_child is permitted as a child of node */
899 if (new_child->type == DOM_DOCUMENT_FRAGMENT_NODE) {
900 /* If this node is a doc fragment, we should test all its
901 * children nodes */
902 dom_node_internal *c;
903 c = new_child->first_child;
904 while (c != NULL) {
905 if (!_dom_node_permitted_child(node, c))
906 return DOM_HIERARCHY_REQUEST_ERR;
907
908 c = c->next;
909 }
910 } else {
911 if (!_dom_node_permitted_child(node, new_child))
912 return DOM_HIERARCHY_REQUEST_ERR;
913 }
914
915 /* Attempting to replace a node with itself is a NOP */
916 if (new_child == old_child) {
917 dom_node_ref(old_child);
918 *result = old_child;
919
920 return DOM_NO_ERR;
921 }
922
923 /* If new_child is already in the tree and
924 * its parent isn't read only, remove it */
925 if (new_child->parent != NULL) {
926 if (_dom_node_readonly(new_child->parent))
927 return DOM_NO_MODIFICATION_ALLOWED_ERR;
928
929 _dom_node_detach(new_child);
930 }
931
932 /* When a Node is attached, it should be removed from the pending
933 * list */
934 dom_node_remove_pending(new_child);
935
936 /* Perform the replacement */
937 _dom_node_replace(old_child, new_child);
938
939 /* Sort out the return value */
940 dom_node_ref(old_child);
941 /* The replaced node should be marded pending */
942 dom_node_mark_pending(old_child);
943 *result = old_child;
944
945 return DOM_NO_ERR;
946 }
947
948 /**
949 * Remove a child from a node
950 *
951 * \param node Node whose child to replace
952 * \param old_child Child to remove
953 * \param result Pointer to location to receive removed node
954 * \return DOM_NO_ERR on success,
955 * DOM_NO_MODIFICATION_ALLOWED_ERR if ::node is readonly
956 * DOM_NOT_FOUND_ERR if ::old_child is not a child of
957 * ::node,
958 * DOM_NOT_SUPPORTED_ERR if ::node is of type Document and
959 * ::new_child is of type
960 * DocumentType or Element.
961 *
962 * The returned node will have its reference count increased. It is
963 * the responsibility of the caller to unref the node once it has
964 * finished with it.
965 */
_dom_node_remove_child(dom_node_internal * node,dom_node_internal * old_child,dom_node_internal ** result)966 dom_exception _dom_node_remove_child(dom_node_internal *node,
967 dom_node_internal *old_child,
968 dom_node_internal **result)
969 {
970 dom_exception err;
971 bool success = true;
972
973 /* We don't support removal of DocumentType or root Element nodes */
974 if (node->type == DOM_DOCUMENT_NODE &&
975 (old_child->type == DOM_DOCUMENT_TYPE_NODE ||
976 old_child->type == DOM_ELEMENT_NODE))
977 return DOM_NOT_SUPPORTED_ERR;
978
979 /* Ensure old_child is a child of node */
980 if (old_child->parent != node)
981 return DOM_NOT_FOUND_ERR;
982
983 /* Ensure node is writable */
984 if (_dom_node_readonly(node))
985 return DOM_NO_MODIFICATION_ALLOWED_ERR;
986
987 /* Dispatch a DOMNodeRemoval event */
988 err = dom_node_dispatch_node_change_event(node->owner, old_child, node,
989 DOM_MUTATION_REMOVAL, &success);
990 if (err != DOM_NO_ERR)
991 return err;
992
993 /* Detach the node */
994 _dom_node_detach(old_child);
995
996 /* When a Node is removed, it should be destroy. When its refcnt is not
997 * zero, it will be added to the document's deletion pending list.
998 * When a Node is removed, its parent should be NULL, but its owner
999 * should remain to be the document. */
1000 dom_node_ref(old_child);
1001 dom_node_try_destroy(old_child);
1002 *result = old_child;
1003
1004 success = true;
1005 err = _dom_dispatch_subtree_modified_event(node->owner, node,
1006 &success);
1007 if (err != DOM_NO_ERR)
1008 return err;
1009
1010 return DOM_NO_ERR;
1011 }
1012
1013 /**
1014 * Append a child to the end of a node's child list
1015 *
1016 * \param node Node to insert into
1017 * \param new_child Node to append
1018 * \param result Pointer to location to receive node being inserted
1019 * \return DOM_NO_ERR on success,
1020 * DOM_HIERARCHY_REQUEST_ERR if ::new_child's type is not
1021 * permitted as a child of ::node,
1022 * or ::new_child is an ancestor of
1023 * ::node (or is ::node itself), or
1024 * ::node is of type Document and a
1025 * second DocumentType or Element is
1026 * being inserted,
1027 * DOM_WRONG_DOCUMENT_ERR if ::new_child was created from a
1028 * different document than ::node,
1029 * DOM_NO_MODIFICATION_ALLOWED_ERR if ::node is readonly, or
1030 * ::new_child's parent is readonly.
1031 *
1032 * If ::new_child is a DocumentFragment, all of its children are inserted.
1033 * If ::new_child is already in the tree, it is first removed.
1034 *
1035 * The returned node will have its reference count increased. It is
1036 * the responsibility of the caller to unref the node once it has
1037 * finished with it.
1038 */
_dom_node_append_child(dom_node_internal * node,dom_node_internal * new_child,dom_node_internal ** result)1039 dom_exception _dom_node_append_child(dom_node_internal *node,
1040 dom_node_internal *new_child,
1041 dom_node_internal **result)
1042 {
1043 /* This is just a veneer over insert_before */
1044 return dom_node_insert_before(node, new_child, NULL, result);
1045 }
1046
1047 /**
1048 * Determine if a node has any children
1049 *
1050 * \param node Node to inspect
1051 * \param result Pointer to location to receive result
1052 * \return DOM_NO_ERR.
1053 */
_dom_node_has_child_nodes(dom_node_internal * node,bool * result)1054 dom_exception _dom_node_has_child_nodes(dom_node_internal *node, bool *result)
1055 {
1056 *result = node->first_child != NULL;
1057
1058 return DOM_NO_ERR;
1059 }
1060
1061 /**
1062 * Clone a DOM node
1063 *
1064 * \param node The node to clone
1065 * \param deep True to deep-clone the node's sub-tree
1066 * \param result Pointer to location to receive result
1067 * \return DOM_NO_ERR on success,
1068 * DOM_NO_MEMORY_ERR on memory exhaustion.
1069 *
1070 * The returned node will already be referenced.
1071 *
1072 * The duplicate node will have no parent and no user data.
1073 *
1074 * If ::node has registered user_data_handlers, then they will be called.
1075 *
1076 * Cloning an Element copies all attributes & their values (including those
1077 * generated by the XML processor to represent defaulted attributes). It
1078 * does not copy any child nodes unless it is a deep copy (this includes
1079 * text contained within the Element, as the text is contained in a child
1080 * Text node).
1081 *
1082 * Cloning an Attr directly, as opposed to cloning as part of an Element,
1083 * returns a specified attribute. Cloning an Attr always clones its children,
1084 * since they represent its value, no matter whether this is a deep clone or
1085 * not.
1086 *
1087 * Cloning an EntityReference automatically constructs its subtree if a
1088 * corresponding Entity is available, no matter whether this is a deep clone
1089 * or not.
1090 *
1091 * Cloning any other type of node simply returns a copy.
1092 *
1093 * Note that cloning an immutable subtree results in a mutable copy, but
1094 * the children of an EntityReference clone are readonly. In addition, clones
1095 * of unspecified Attr nodes are specified.
1096 *
1097 * \todo work out what happens when cloning Document, DocumentType, Entity
1098 * and Notation nodes.
1099 *
1100 * Note: we adopt a OO paradigm, this clone_node just provide a basic operation
1101 * of clone. Special clones like Attr/EntitiReference stated above should
1102 * provide their overload of this interface in their implementation file.
1103 */
_dom_node_clone_node(dom_node_internal * node,bool deep,dom_node_internal ** result)1104 dom_exception _dom_node_clone_node(dom_node_internal *node, bool deep,
1105 dom_node_internal **result)
1106 {
1107 dom_node_internal *n, *child, *r;
1108 dom_exception err;
1109 dom_user_data *ud;
1110
1111 assert(node->owner != NULL);
1112
1113 err = dom_node_copy(node, &n);
1114 if (err != DOM_NO_ERR) {
1115 return err;
1116 }
1117
1118 if (deep) {
1119 child = node->first_child;
1120 while (child != NULL) {
1121 err = dom_node_clone_node(child, deep, (void *) &r);
1122 if (err != DOM_NO_ERR) {
1123 dom_node_unref(n);
1124 return err;
1125 }
1126
1127 err = dom_node_append_child(n, r, (void *) &r);
1128 if (err != DOM_NO_ERR) {
1129 dom_node_unref(n);
1130 return err;
1131 }
1132
1133 /* Clean up the new node, we have reference it two
1134 * times */
1135 dom_node_unref(r);
1136 dom_node_unref(r);
1137 child = child->next;
1138 }
1139 }
1140
1141 *result = n;
1142
1143 /* Call the dom_user_data_handlers */
1144 ud = node->user_data;
1145 while (ud != NULL) {
1146 if (ud->handler != NULL)
1147 ud->handler(DOM_NODE_CLONED, ud->key, ud->data,
1148 (dom_node *) node, (dom_node *) n);
1149 ud = ud->next;
1150 }
1151
1152 return DOM_NO_ERR;
1153 }
1154
1155 /**
1156 * Normalize a DOM node
1157 *
1158 * \param node The node to normalize
1159 * \return DOM_NO_ERR.
1160 *
1161 * Puts all Text nodes in the full depth of the sub-tree beneath ::node,
1162 * including Attr nodes into "normal" form, where only structure separates
1163 * Text nodes.
1164 */
_dom_node_normalize(dom_node_internal * node)1165 dom_exception _dom_node_normalize(dom_node_internal *node)
1166 {
1167 dom_node_internal *n, *p;
1168 dom_exception err;
1169
1170 p = node->first_child;
1171 if (p == NULL)
1172 return DOM_NO_ERR;
1173
1174 n = p->next;
1175
1176 while (n != NULL) {
1177 if (n->type == DOM_TEXT_NODE && p->type == DOM_TEXT_NODE) {
1178 err = _dom_merge_adjacent_text(p, n);
1179 if (err != DOM_NO_ERR)
1180 return err;
1181
1182 _dom_node_detach(n);
1183 dom_node_unref(n);
1184 n = p->next;
1185 continue;
1186 }
1187 if (n->type != DOM_TEXT_NODE) {
1188 err = dom_node_normalize(n);
1189 if (err != DOM_NO_ERR)
1190 return err;
1191 }
1192 p = n;
1193 n = n->next;
1194 }
1195
1196 return DOM_NO_ERR;
1197 }
1198
1199 /**
1200 * Test whether the DOM implementation implements a specific feature and
1201 * that feature is supported by the node.
1202 *
1203 * \param node The node to test
1204 * \param feature The name of the feature to test
1205 * \param version The version number of the feature to test
1206 * \param result Pointer to location to receive result
1207 * \return DOM_NO_ERR.
1208 */
_dom_node_is_supported(dom_node_internal * node,dom_string * feature,dom_string * version,bool * result)1209 dom_exception _dom_node_is_supported(dom_node_internal *node,
1210 dom_string *feature, dom_string *version,
1211 bool *result)
1212 {
1213 bool has;
1214
1215 UNUSED(node);
1216
1217 dom_implementation_has_feature(dom_string_data(feature),
1218 dom_string_data(version), &has);
1219
1220 *result = has;
1221
1222 return DOM_NO_ERR;
1223 }
1224
1225 /**
1226 * Retrieve the namespace of a DOM node
1227 *
1228 * \param node The node to retrieve the namespace of
1229 * \param result Pointer to location to receive node's namespace
1230 * \return DOM_NO_ERR.
1231 *
1232 * The returned string will have its reference count increased. It is
1233 * the responsibility of the caller to unref the string once it has
1234 * finished with it.
1235 */
_dom_node_get_namespace(dom_node_internal * node,dom_string ** result)1236 dom_exception _dom_node_get_namespace(dom_node_internal *node,
1237 dom_string **result)
1238 {
1239 assert(node->owner != NULL);
1240
1241 /* If there is a namespace, increase its reference count */
1242 if (node->namespace != NULL)
1243 *result = dom_string_ref(node->namespace);
1244 else
1245 *result = NULL;
1246
1247 return DOM_NO_ERR;
1248 }
1249
1250 /**
1251 * Retrieve the prefix of a DOM node
1252 *
1253 * \param node The node to retrieve the prefix of
1254 * \param result Pointer to location to receive node's prefix
1255 * \return DOM_NO_ERR.
1256 *
1257 * The returned string will have its reference count increased. It is
1258 * the responsibility of the caller to unref the string once it has
1259 * finished with it.
1260 */
_dom_node_get_prefix(dom_node_internal * node,dom_string ** result)1261 dom_exception _dom_node_get_prefix(dom_node_internal *node,
1262 dom_string **result)
1263 {
1264 assert(node->owner != NULL);
1265
1266 /* If there is a prefix, increase its reference count */
1267 if (node->prefix != NULL)
1268 *result = dom_string_ref(node->prefix);
1269 else
1270 *result = NULL;
1271
1272 return DOM_NO_ERR;
1273 }
1274
1275 /**
1276 * Set the prefix of a DOM node
1277 *
1278 * \param node The node to set the prefix of
1279 * \param prefix Pointer to prefix string
1280 * \return DOM_NO_ERR on success,
1281 * DOM_INVALID_CHARACTER_ERR if the specified prefix contains
1282 * an illegal character,
1283 * DOM_NO_MODIFICATION_ALLOWED_ERR if ::node is readonly,
1284 * DOM_NAMESPACE_ERR if the specified prefix is
1285 * malformed, if the namespaceURI of
1286 * ::node is null, if the specified
1287 * prefix is "xml" and the
1288 * namespaceURI is different from
1289 * "http://www.w3.org/XML/1998/namespace",
1290 * if ::node is an attribute and the
1291 * specified prefix is "xmlns" and
1292 * the namespaceURI is different from
1293 * "http://www.w3.org/2000/xmlns",
1294 * or if this node is an attribute
1295 * and the qualifiedName of ::node
1296 * is "xmlns".
1297 */
_dom_node_set_prefix(dom_node_internal * node,dom_string * prefix)1298 dom_exception _dom_node_set_prefix(dom_node_internal *node,
1299 dom_string *prefix)
1300 {
1301 /* Only Element and Attribute nodes created using
1302 * namespace-aware methods may have a prefix */
1303 if ((node->type != DOM_ELEMENT_NODE &&
1304 node->type != DOM_ATTRIBUTE_NODE) ||
1305 node->namespace == NULL) {
1306 return DOM_NO_ERR;
1307 }
1308
1309 /** \todo validate prefix */
1310
1311 /* Ensure node is writable */
1312 if (_dom_node_readonly(node)) {
1313 return DOM_NO_MODIFICATION_ALLOWED_ERR;
1314 }
1315
1316 /* No longer want existing prefix */
1317 if (node->prefix != NULL) {
1318 dom_string_unref(node->prefix);
1319 }
1320
1321 /* Set the prefix */
1322 if (prefix != NULL) {
1323 /* Empty string is treated as NULL */
1324 if (dom_string_length(prefix) == 0) {
1325 node->prefix = NULL;
1326 } else {
1327 node->prefix = dom_string_ref(prefix);
1328 }
1329 } else {
1330 node->prefix = NULL;
1331 }
1332
1333 return DOM_NO_ERR;
1334 }
1335
1336 /**
1337 * Retrieve the local part of a node's qualified name
1338 *
1339 * \param node The node to retrieve the local name of
1340 * \param result Pointer to location to receive local name
1341 * \return DOM_NO_ERR.
1342 *
1343 * The returned string will have its reference count increased. It is
1344 * the responsibility of the caller to unref the string once it has
1345 * finished with it.
1346 */
_dom_node_get_local_name(dom_node_internal * node,dom_string ** result)1347 dom_exception _dom_node_get_local_name(dom_node_internal *node,
1348 dom_string **result)
1349 {
1350 assert(node->owner != NULL);
1351
1352 /* Only Element and Attribute nodes may have a local name */
1353 if (node->type != DOM_ELEMENT_NODE &&
1354 node->type != DOM_ATTRIBUTE_NODE) {
1355 *result = NULL;
1356 return DOM_NO_ERR;
1357 }
1358
1359 /* The node may have a local name, reference it if so */
1360 if (node->name != NULL)
1361 *result = dom_string_ref(node->name);
1362 else
1363 *result = NULL;
1364
1365 return DOM_NO_ERR;
1366 }
1367
1368 /**
1369 * Determine if a node has any attributes
1370 *
1371 * \param node Node to inspect
1372 * \param result Pointer to location to receive result
1373 * \return DOM_NO_ERR.
1374 */
_dom_node_has_attributes(dom_node_internal * node,bool * result)1375 dom_exception _dom_node_has_attributes(dom_node_internal *node, bool *result)
1376 {
1377 UNUSED(node);
1378 *result = false;
1379
1380 return DOM_NO_ERR;
1381 }
1382
1383 /**
1384 * Retrieve the base URI of a DOM node
1385 *
1386 * \param node The node to retrieve the base URI of
1387 * \param result Pointer to location to receive base URI
1388 * \return DOM_NO_ERR.
1389 *
1390 * The returned string will have its reference count increased. It is
1391 * the responsibility of the caller to unref the string once it has
1392 * finished with it.
1393 *
1394 * We don't support this API now, so this function call should always
1395 * return DOM_NOT_SUPPORTED_ERR.
1396 */
_dom_node_get_base(dom_node_internal * node,dom_string ** result)1397 dom_exception _dom_node_get_base(dom_node_internal *node,
1398 dom_string **result)
1399 {
1400 struct dom_document *doc = node->owner;
1401 assert(doc != NULL);
1402
1403 return _dom_document_get_uri(doc, result);
1404 }
1405
1406 /**
1407 * Compare the positions of two nodes in a DOM tree
1408 *
1409 * \param node The reference node
1410 * \param other The node to compare
1411 * \param result Pointer to location to receive result
1412 * \return DOM_NO_ERR on success,
1413 * DOM_NOT_SUPPORTED_ERR when the nodes are from different DOM
1414 * implementations.
1415 *
1416 * The result is a bitfield of dom_document_position values.
1417 *
1418 * We don't support this API now, so this function call should always
1419 * return DOM_NOT_SUPPORTED_ERR.
1420 */
_dom_node_compare_document_position(dom_node_internal * node,dom_node_internal * other,uint16_t * result)1421 dom_exception _dom_node_compare_document_position(dom_node_internal *node,
1422 dom_node_internal *other, uint16_t *result)
1423 {
1424 UNUSED(node);
1425 UNUSED(other);
1426 UNUSED(result);
1427
1428 return DOM_NOT_SUPPORTED_ERR;
1429 }
1430
1431 /**
1432 * Retrieve the text content of a DOM node
1433 *
1434 * \param node The node to retrieve the text content of
1435 * \param result Pointer to location to receive text content
1436 * \return DOM_NO_ERR.
1437 *
1438 * The returned string will have its reference count increased. It is
1439 * the responsibility of the caller to unref the string once it has
1440 * finished with it.
1441 *
1442 * If there is no text content in the code, NULL will returned in \a result.
1443 *
1444 * DOM3Core states that this can raise DOMSTRING_SIZE_ERR. It will not in
1445 * this implementation; dom_strings are unbounded.
1446 */
_dom_node_get_text_content(dom_node_internal * node,dom_string ** result)1447 dom_exception _dom_node_get_text_content(dom_node_internal *node,
1448 dom_string **result)
1449 {
1450 dom_node_internal *n;
1451 dom_string *str = NULL;
1452 dom_string *ret = NULL;
1453
1454 assert(node->owner != NULL);
1455
1456 for (n = node->first_child; n != NULL; n = n->next) {
1457 if (n->type == DOM_COMMENT_NODE ||
1458 n->type == DOM_PROCESSING_INSTRUCTION_NODE)
1459 continue;
1460 dom_node_get_text_content(n, (str == NULL) ? &str : &ret);
1461 if (ret != NULL) {
1462 dom_string *new_str;
1463 dom_string_concat(str, ret, &new_str);
1464 dom_string_unref(str);
1465 dom_string_unref(ret);
1466 str = new_str;
1467 }
1468 }
1469
1470 *result = str;
1471
1472 return DOM_NO_ERR;
1473 }
1474
1475 /**
1476 * Set the text content of a DOM node
1477 *
1478 * \param node The node to set the text content of
1479 * \param content New text content for node
1480 * \return DOM_NO_ERR on success,
1481 * DOM_NO_MODIFICATION_ALLOWED_ERR if ::node is readonly.
1482 *
1483 * Any child nodes ::node may have are removed and replaced with a single
1484 * Text node containing the new content.
1485 */
_dom_node_set_text_content(dom_node_internal * node,dom_string * content)1486 dom_exception _dom_node_set_text_content(dom_node_internal *node,
1487 dom_string *content)
1488 {
1489 dom_node_internal *n, *p, *r;
1490 dom_document *doc;
1491 dom_text *text;
1492 dom_exception err;
1493
1494 n = node->first_child;
1495
1496 while (n != NULL) {
1497 p = n;
1498 n = n->next;
1499 /* Add the (void *) casting to avoid gcc warning:
1500 * dereferencing type-punned pointer will break
1501 * strict-aliasing rules */
1502 err = dom_node_remove_child(node, p, (void *) &r);
1503 if (err != DOM_NO_ERR)
1504 return err;
1505 /* The returned node was reffed, so unref it */
1506 dom_node_unref(r);
1507 }
1508
1509 doc = node->owner;
1510 assert(doc != NULL);
1511
1512 err = dom_document_create_text_node(doc, content, &text);
1513 if (err != DOM_NO_ERR)
1514 return err;
1515
1516 err = dom_node_append_child(node, text, (void *) &r);
1517
1518 /* The node is held alive as a child here, so unref it */
1519 dom_node_unref(text);
1520 /* And unref it a second time because append_child reffed it too */
1521 dom_node_unref(r);
1522
1523 return err;
1524 }
1525
1526 /**
1527 * Determine if two DOM nodes are the same
1528 *
1529 * \param node The node to compare
1530 * \param other The node to compare against
1531 * \param result Pointer to location to receive result
1532 * \return DOM_NO_ERR.
1533 *
1534 * This tests if the two nodes reference the same object.
1535 */
_dom_node_is_same(dom_node_internal * node,dom_node_internal * other,bool * result)1536 dom_exception _dom_node_is_same(dom_node_internal *node,
1537 dom_node_internal *other, bool *result)
1538 {
1539 *result = (node == other);
1540
1541 return DOM_NO_ERR;
1542 }
1543
1544 /**
1545 * Lookup the prefix associated with the given namespace URI
1546 *
1547 * \param node The node to start prefix search from
1548 * \param namespace The namespace URI
1549 * \param result Pointer to location to receive result
1550 * \return DOM_NO_ERR.
1551 *
1552 * The returned string will have its reference count increased. It is
1553 * the responsibility of the caller to unref the string once it has
1554 * finished with it.
1555 */
_dom_node_lookup_prefix(dom_node_internal * node,dom_string * namespace,dom_string ** result)1556 dom_exception _dom_node_lookup_prefix(dom_node_internal *node,
1557 dom_string *namespace, dom_string **result)
1558 {
1559 if (node->parent != NULL)
1560 return dom_node_lookup_prefix(node, namespace, result);
1561 else
1562 *result = NULL;
1563
1564 return DOM_NO_ERR;
1565 }
1566
1567 /**
1568 * Determine if the specified namespace is the default namespace
1569 *
1570 * \param node The node to query
1571 * \param namespace The namespace URI to test
1572 * \param result Pointer to location to receive result
1573 * \return DOM_NO_ERR.
1574 */
_dom_node_is_default_namespace(dom_node_internal * node,dom_string * namespace,bool * result)1575 dom_exception _dom_node_is_default_namespace(dom_node_internal *node,
1576 dom_string *namespace, bool *result)
1577 {
1578 if (node->parent != NULL)
1579 return dom_node_is_default_namespace(node, namespace, result);
1580 else
1581 *result = false;
1582 return DOM_NO_ERR;
1583 }
1584
1585 /**
1586 * Lookup the namespace URI associated with the given prefix
1587 *
1588 * \param node The node to start namespace search from
1589 * \param prefix The prefix to look for, or NULL to find default.
1590 * \param result Pointer to location to receive result
1591 * \return DOM_NO_ERR.
1592 *
1593 * The returned string will have its reference count increased. It is
1594 * the responsibility of the caller to unref the string once it has
1595 * finished with it.
1596 */
_dom_node_lookup_namespace(dom_node_internal * node,dom_string * prefix,dom_string ** result)1597 dom_exception _dom_node_lookup_namespace(dom_node_internal *node,
1598 dom_string *prefix, dom_string **result)
1599 {
1600 if (node->parent != NULL)
1601 return dom_node_lookup_namespace(node->parent, prefix, result);
1602 else
1603 *result = NULL;
1604
1605 return DOM_NO_ERR;
1606 }
1607
1608 /**
1609 * Determine if two DOM nodes are equal
1610 *
1611 * \param node The node to compare
1612 * \param other The node to compare against
1613 * \param result Pointer to location to receive result
1614 * \return DOM_NO_ERR.
1615 *
1616 * Two nodes are equal iff:
1617 * + They are of the same type
1618 * + nodeName, localName, namespaceURI, prefix, nodeValue are equal
1619 * + The node attributes are equal
1620 * + The child nodes are equal
1621 *
1622 * Two DocumentType nodes are equal iff:
1623 * + publicId, systemId, internalSubset are equal
1624 * + The node entities are equal
1625 * + The node notations are equal
1626 * TODO: in document_type, we should override this virtual function
1627 * TODO: actually handle DocumentType nodes differently
1628 */
_dom_node_is_equal(dom_node_internal * node,dom_node_internal * other,bool * result)1629 dom_exception _dom_node_is_equal(dom_node_internal *node,
1630 dom_node_internal *other, bool *result)
1631 {
1632 dom_exception err = DOM_NO_ERR;
1633 dom_namednodemap *m1 = NULL, *m2 = NULL;
1634 dom_nodelist *l1 = NULL, *l2 = NULL;
1635 *result = false;
1636
1637 /* Compare the node types */
1638 if (node->type != other->type){
1639 /* different */
1640 err = DOM_NO_ERR;
1641 goto cleanup;
1642 }
1643
1644 assert(node->owner != NULL);
1645 assert(other->owner != NULL);
1646
1647 /* Compare node name */
1648 if (dom_string_isequal(node->name, other->name) == false) {
1649 /* different */
1650 goto cleanup;
1651 }
1652
1653 /* Compare prefix */
1654 if (dom_string_isequal(node->prefix, other->prefix) == false) {
1655 /* different */
1656 goto cleanup;
1657 }
1658
1659 /* Compare namespace URI */
1660 if (dom_string_isequal(node->namespace, other->namespace) == false) {
1661 /* different */
1662 goto cleanup;
1663 }
1664
1665 /* Compare node value */
1666 if (dom_string_isequal(node->value, other->value) == false) {
1667 /* different */
1668 goto cleanup;
1669 }
1670
1671 /* Compare the attributes */
1672 err = dom_node_get_attributes(node, &m1);
1673 if (err != DOM_NO_ERR) {
1674 /* error */
1675 goto cleanup;
1676 }
1677
1678 err = dom_node_get_attributes(other, &m2);
1679 if (err != DOM_NO_ERR) {
1680 /* error */
1681 goto cleanup;
1682 }
1683
1684 if (dom_namednodemap_equal(m1, m2) == false) {
1685 /* different */
1686 goto cleanup;
1687 }
1688
1689 /* Compare the children */
1690 err = dom_node_get_child_nodes(node, &l1);
1691 if (err != DOM_NO_ERR) {
1692 /* error */
1693 goto cleanup;
1694 }
1695
1696 err = dom_node_get_child_nodes(other, &l2);
1697 if (err != DOM_NO_ERR) {
1698 /* error */
1699 goto cleanup;
1700 }
1701
1702 if (dom_nodelist_equal(l1, l2) == false) {
1703 /* different */
1704 goto cleanup;
1705 }
1706
1707 *result = true;
1708
1709 cleanup:
1710 if (m1 != NULL)
1711 dom_namednodemap_unref(m1);
1712 if (m2 != NULL)
1713 dom_namednodemap_unref(m2);
1714
1715 if (l1 != NULL)
1716 dom_nodelist_unref(l1);
1717 if (l2 != NULL)
1718 dom_nodelist_unref(l2);
1719
1720 return err;
1721 }
1722
1723 /**
1724 * Retrieve an object which implements the specialized APIs of the specified
1725 * feature and version.
1726 *
1727 * \param node The node to query
1728 * \param feature The requested feature
1729 * \param version The version number of the feature
1730 * \param result Pointer to location to receive result
1731 * \return DOM_NO_ERR.
1732 */
_dom_node_get_feature(dom_node_internal * node,dom_string * feature,dom_string * version,void ** result)1733 dom_exception _dom_node_get_feature(dom_node_internal *node,
1734 dom_string *feature, dom_string *version,
1735 void **result)
1736 {
1737 bool has;
1738
1739 dom_implementation_has_feature(dom_string_data(feature),
1740 dom_string_data(version), &has);
1741
1742 if (has) {
1743 *result = node;
1744 } else {
1745 *result = NULL;
1746 }
1747
1748 return DOM_NO_ERR;
1749 }
1750
1751 /**
1752 * Associate an object to a key on this node
1753 *
1754 * \param node The node to insert object into
1755 * \param key The key associated with the object
1756 * \param data The object to associate with key, or NULL to remove
1757 * \param handler User handler function, or NULL if none
1758 * \param result Pointer to location to receive previously associated object
1759 * \return DOM_NO_ERR.
1760 */
_dom_node_set_user_data(dom_node_internal * node,dom_string * key,void * data,dom_user_data_handler handler,void ** result)1761 dom_exception _dom_node_set_user_data(dom_node_internal *node,
1762 dom_string *key, void *data,
1763 dom_user_data_handler handler, void **result)
1764 {
1765 struct dom_user_data *ud = NULL;
1766 void *prevdata = NULL;
1767
1768 /* Search for user data */
1769 for (ud = node->user_data; ud != NULL; ud = ud->next) {
1770 if (dom_string_isequal(ud->key, key))
1771 break;
1772 };
1773
1774 /* Remove it, if found and no new data */
1775 if (data == NULL && ud != NULL) {
1776 dom_string_unref(ud->key);
1777
1778 if (ud->next != NULL)
1779 ud->next->prev = ud->prev;
1780 if (ud->prev != NULL)
1781 ud->prev->next = ud->next;
1782 else
1783 node->user_data = ud->next;
1784
1785 *result = ud->data;
1786
1787 free(ud);
1788
1789 return DOM_NO_ERR;
1790 }
1791
1792 /* Otherwise, create a new user data object if one wasn't found */
1793 if (ud == NULL) {
1794 ud = malloc(sizeof(struct dom_user_data));
1795 if (ud == NULL)
1796 return DOM_NO_MEM_ERR;
1797
1798 dom_string_ref(key);
1799 ud->key = key;
1800 ud->data = NULL;
1801 ud->handler = NULL;
1802
1803 /* Insert into list */
1804 ud->prev = NULL;
1805 ud->next = node->user_data;
1806 if (node->user_data)
1807 node->user_data->prev = ud;
1808 node->user_data = ud;
1809 }
1810
1811 prevdata = ud->data;
1812
1813 /* And associate data with it */
1814 ud->data = data;
1815 ud->handler = handler;
1816
1817 *result = prevdata;
1818
1819 return DOM_NO_ERR;
1820 }
1821
1822 /**
1823 * Retrieves the object associated to a key on this node
1824 *
1825 * \param node The node to retrieve object from
1826 * \param key The key to search for
1827 * \param result Pointer to location to receive result
1828 * \return DOM_NO_ERR.
1829 */
_dom_node_get_user_data(dom_node_internal * node,dom_string * key,void ** result)1830 dom_exception _dom_node_get_user_data(dom_node_internal *node,
1831 dom_string *key, void **result)
1832 {
1833 struct dom_user_data *ud = NULL;
1834
1835 /* Search for user data */
1836 for (ud = node->user_data; ud != NULL; ud = ud->next) {
1837 if (dom_string_isequal(ud->key, key))
1838 break;
1839 };
1840
1841 if (ud != NULL)
1842 *result = ud->data;
1843 else
1844 *result = NULL;
1845
1846 return DOM_NO_ERR;
1847 }
1848
1849
1850 /*--------------------------------------------------------------------------*/
1851
1852 /* The protected virtual functions */
1853
1854 /* Copy the internal attributes of a Node from old to new */
_dom_node_copy(dom_node_internal * old,dom_node_internal ** copy)1855 dom_exception _dom_node_copy(dom_node_internal *old, dom_node_internal **copy)
1856 {
1857 dom_node_internal *new_node;
1858 dom_exception err;
1859
1860 new_node = malloc(sizeof(dom_node_internal));
1861 if (new_node == NULL)
1862 return DOM_NO_MEM_ERR;
1863
1864 err = _dom_node_copy_internal(old, new_node);
1865 if (err != DOM_NO_ERR) {
1866 free(new_node);
1867 return err;
1868 }
1869
1870 *copy = new_node;
1871
1872 return DOM_NO_ERR;
1873 }
1874
_dom_node_copy_internal(dom_node_internal * old,dom_node_internal * new)1875 dom_exception _dom_node_copy_internal(dom_node_internal *old,
1876 dom_node_internal *new)
1877 {
1878 new->base.vtable = old->base.vtable;
1879 new->vtable = old->vtable;
1880
1881 new->name = dom_string_ref(old->name);
1882
1883 /* Value - see below */
1884
1885 new->type = old->type;
1886 new->parent = NULL;
1887 new->first_child = NULL;
1888 new->last_child = NULL;
1889 new->previous = NULL;
1890 new->next = NULL;
1891
1892 assert(old->owner != NULL);
1893
1894 new->owner = old->owner;
1895
1896 if (old->namespace != NULL)
1897 new->namespace = dom_string_ref(old->namespace);
1898 else
1899 new->namespace = NULL;
1900
1901 if (old->prefix != NULL)
1902 new->prefix = dom_string_ref(old->prefix);
1903 else
1904 new->prefix = NULL;
1905
1906 new->user_data = NULL;
1907 new->base.refcnt = 1;
1908
1909 list_init(&new->pending_list);
1910
1911 /* Value */
1912 if (old->value != NULL) {
1913 dom_string_ref(old->value);
1914
1915 new->value = old->value;
1916 } else {
1917 new->value = NULL;
1918 }
1919
1920 /* The new copyed node has no parent,
1921 * so it should be put in the pending list. */
1922 dom_node_mark_pending(new);
1923
1924 /* Intialise the EventTarget interface */
1925 return _dom_event_target_internal_initialise(&new->eti);
1926 }
1927
1928
1929 /*--------------------------------------------------------------------------*/
1930
1931 /* The helper functions */
1932
1933 /**
1934 * Determine if a node is permitted as a child of another node
1935 *
1936 * \param parent Prospective parent
1937 * \param child Prospective child
1938 * \return true if ::child is permitted as a child of ::parent, false otherwise.
1939 */
_dom_node_permitted_child(const dom_node_internal * parent,const dom_node_internal * child)1940 bool _dom_node_permitted_child(const dom_node_internal *parent,
1941 const dom_node_internal *child)
1942 {
1943 bool valid = false;
1944
1945 /* See DOM3Core $1.1.1 for details */
1946
1947 switch (parent->type) {
1948 case DOM_ELEMENT_NODE:
1949 case DOM_ENTITY_REFERENCE_NODE:
1950 case DOM_ENTITY_NODE:
1951 case DOM_DOCUMENT_FRAGMENT_NODE:
1952 valid = (child->type == DOM_ELEMENT_NODE ||
1953 child->type == DOM_TEXT_NODE ||
1954 child->type == DOM_COMMENT_NODE ||
1955 child->type == DOM_PROCESSING_INSTRUCTION_NODE ||
1956 child->type == DOM_CDATA_SECTION_NODE ||
1957 child->type == DOM_ENTITY_REFERENCE_NODE);
1958 break;
1959
1960 case DOM_ATTRIBUTE_NODE:
1961 valid = (child->type == DOM_TEXT_NODE ||
1962 child->type == DOM_ENTITY_REFERENCE_NODE);
1963 break;
1964
1965 case DOM_TEXT_NODE:
1966 case DOM_CDATA_SECTION_NODE:
1967 case DOM_PROCESSING_INSTRUCTION_NODE:
1968 case DOM_COMMENT_NODE:
1969 case DOM_DOCUMENT_TYPE_NODE:
1970 case DOM_NOTATION_NODE:
1971 case DOM_NODE_TYPE_COUNT:
1972 valid = false;
1973 break;
1974
1975 case DOM_DOCUMENT_NODE:
1976 valid = (child->type == DOM_ELEMENT_NODE ||
1977 child->type == DOM_PROCESSING_INSTRUCTION_NODE ||
1978 child->type == DOM_COMMENT_NODE ||
1979 child->type == DOM_DOCUMENT_TYPE_NODE);
1980
1981 /* Ensure that the document doesn't already
1982 * have a root element */
1983 if (child->type == DOM_ELEMENT_NODE) {
1984 dom_node_internal *n;
1985 for (n = parent->first_child;
1986 n != NULL; n = n->next) {
1987 if (n->type == DOM_ELEMENT_NODE)
1988 valid = false;
1989 }
1990 }
1991
1992 /* Ensure that the document doesn't already
1993 * have a document type */
1994 if (child->type == DOM_DOCUMENT_TYPE_NODE) {
1995 dom_node_internal *n;
1996 for (n = parent->first_child;
1997 n != NULL; n = n->next) {
1998 if (n->type == DOM_DOCUMENT_TYPE_NODE)
1999 valid = false;
2000 }
2001 }
2002
2003 break;
2004 }
2005
2006 return valid;
2007 }
2008
2009 /**
2010 * Determine if a node is read only
2011 *
2012 * \param node The node to consider
2013 */
_dom_node_readonly(const dom_node_internal * node)2014 bool _dom_node_readonly(const dom_node_internal *node)
2015 {
2016 const dom_node_internal *n = node;
2017
2018 /* DocumentType and Notation ns are read only */
2019 if (n->type == DOM_DOCUMENT_TYPE_NODE ||
2020 n->type == DOM_NOTATION_NODE)
2021 return true;
2022
2023 /* Some Attr node are readonly */
2024 if (n->type == DOM_ATTRIBUTE_NODE)
2025 return _dom_attr_readonly((const dom_attr *) n);
2026
2027 /* Entity ns and their descendants are read only
2028 * EntityReference ns and their descendants are read only */
2029 for (n = node; n != NULL; n = n->parent) {
2030 if (n->type == DOM_ENTITY_NODE
2031 || n->type == DOM_ENTITY_REFERENCE_NODE)
2032 return true;
2033 }
2034
2035 /* Otherwise, it's writable */
2036 return false;
2037 }
2038
2039 /**
2040 * Attach a node to the tree
2041 *
2042 * \param node The node to attach
2043 * \param parent Node to attach ::node as child of
2044 * \param previous Previous node in sibling list, or NULL if none
2045 * \param next Next node in sibling list, or NULL if none
2046 * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
2047 */
_dom_node_attach(dom_node_internal * node,dom_node_internal * parent,dom_node_internal * previous,dom_node_internal * next)2048 dom_exception _dom_node_attach(dom_node_internal *node,
2049 dom_node_internal *parent, dom_node_internal *previous,
2050 dom_node_internal *next)
2051 {
2052 return _dom_node_attach_range(node, node, parent, previous, next);
2053 }
2054
2055 /**
2056 * Detach a node from the tree
2057 *
2058 * \param node The node to detach
2059 */
_dom_node_detach(dom_node_internal * node)2060 void _dom_node_detach(dom_node_internal *node)
2061 {
2062 /* When a Node is not in the document tree, it must be in the
2063 * pending list */
2064 dom_node_mark_pending(node);
2065
2066 _dom_node_detach_range(node, node);
2067 }
2068
2069 /**
2070 * Attach a range of nodes to the tree
2071 *
2072 * \param first First node in the range
2073 * \param last Last node in the range
2074 * \param parent Node to attach range to
2075 * \param previous Previous node in sibling list, or NULL if none
2076 * \param next Next node in sibling list, or NULL if none
2077 * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
2078 *
2079 * The range is assumed to be a linked list of sibling nodes.
2080 */
_dom_node_attach_range(dom_node_internal * first,dom_node_internal * last,dom_node_internal * parent,dom_node_internal * previous,dom_node_internal * next)2081 dom_exception _dom_node_attach_range(dom_node_internal *first,
2082 dom_node_internal *last,
2083 dom_node_internal *parent,
2084 dom_node_internal *previous,
2085 dom_node_internal *next)
2086 {
2087 dom_exception err;
2088 bool success = true;
2089 dom_node_internal *n;
2090
2091 first->previous = previous;
2092 last->next = next;
2093
2094 if (previous != NULL)
2095 previous->next = first;
2096 else
2097 parent->first_child = first;
2098
2099 if (next != NULL)
2100 next->previous = last;
2101 else
2102 parent->last_child = last;
2103
2104 for (n = first; n != last->next; n = n->next) {
2105 n->parent = parent;
2106 /* Dispatch a DOMNodeInserted event */
2107 err = dom_node_dispatch_node_change_event(parent->owner,
2108 n, parent, DOM_MUTATION_ADDITION, &success);
2109 if (err != DOM_NO_ERR)
2110 return err;
2111 }
2112
2113 success = true;
2114 err = _dom_dispatch_subtree_modified_event(parent->owner, parent,
2115 &success);
2116 if (err != DOM_NO_ERR)
2117 return err;
2118
2119 return DOM_NO_ERR;
2120 }
2121
2122 /**
2123 * Detach a range of nodes from the tree
2124 *
2125 * \param first The first node in the range
2126 * \param last The last node in the range
2127 *
2128 * The range is assumed to be a linked list of sibling nodes.
2129 */
_dom_node_detach_range(dom_node_internal * first,dom_node_internal * last)2130 dom_exception _dom_node_detach_range(dom_node_internal *first,
2131 dom_node_internal *last)
2132 {
2133 bool success = true;
2134 dom_node_internal *parent;
2135 dom_node_internal *n;
2136 dom_exception err = DOM_NO_ERR;
2137
2138 if (first->previous != NULL)
2139 first->previous->next = last->next;
2140 else
2141 first->parent->first_child = last->next;
2142
2143 if (last->next != NULL)
2144 last->next->previous = first->previous;
2145 else
2146 last->parent->last_child = first->previous;
2147
2148 parent = first->parent;
2149 for (n = first; n != last->next; n = n->next) {
2150 /* Dispatch a DOMNodeRemoval event */
2151 err = dom_node_dispatch_node_change_event(n->owner, n,
2152 n->parent, DOM_MUTATION_REMOVAL, &success);
2153
2154 n->parent = NULL;
2155 }
2156
2157 success = true;
2158 _dom_dispatch_subtree_modified_event(parent->owner, parent,
2159 &success);
2160
2161 first->previous = NULL;
2162 last->next = NULL;
2163
2164 return err;
2165 }
2166
2167 /**
2168 * Replace a node in the tree
2169 *
2170 * \param old Node to replace
2171 * \param replacement Replacement node
2172 *
2173 * This is not implemented in terms of attach/detach in case
2174 * we want to perform any special replacement-related behaviour
2175 * at a later date. If the replacement is essentially empty (either NULL
2176 * or an empty document fragment node) then this essentially just removes
2177 * the old node from its parent. It is up to the caller to deal with that.
2178 */
_dom_node_replace(dom_node_internal * old,dom_node_internal * replacement)2179 void _dom_node_replace(dom_node_internal *old,
2180 dom_node_internal *replacement)
2181 {
2182 dom_node_internal *first, *last;
2183 dom_node_internal *n;
2184
2185 if (replacement->type == DOM_DOCUMENT_FRAGMENT_NODE) {
2186 first = replacement->first_child;
2187 last = replacement->last_child;
2188
2189 replacement->first_child = replacement->last_child = NULL;
2190 } else {
2191 first = replacement;
2192 last = replacement;
2193 }
2194
2195 if (first == NULL) {
2196 /* All we're doing is removing old */
2197 if (old->previous == NULL) {
2198 old->parent->first_child = old->next;
2199 }
2200 if (old->next == NULL) {
2201 old->parent->last_child = old->previous;
2202 }
2203 old->previous = old->next = old->parent = NULL;
2204 return;
2205 }
2206
2207 /* We're replacing old with first-to-last */
2208 first->previous = old->previous;
2209 last->next = old->next;
2210
2211 if (old->previous != NULL)
2212 old->previous->next = first;
2213 else
2214 old->parent->first_child = first;
2215
2216 if (old->next != NULL)
2217 old->next->previous = last;
2218 else
2219 old->parent->last_child = last;
2220
2221 for (n = first; n != NULL && n != last->next; n = n->next) {
2222 n->parent = old->parent;
2223 }
2224
2225 old->previous = old->next = old->parent = NULL;
2226 }
2227
2228 /**
2229 * Merge two adjacent text nodes into one text node.
2230 *
2231 * \param p The first text node
2232 * \param n The second text node
2233 * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
2234 */
_dom_merge_adjacent_text(dom_node_internal * p,dom_node_internal * n)2235 dom_exception _dom_merge_adjacent_text(dom_node_internal *p,
2236 dom_node_internal *n)
2237 {
2238 dom_string *str;
2239 dom_exception err;
2240
2241 assert(p->type == DOM_TEXT_NODE);
2242 assert(n->type == DOM_TEXT_NODE);
2243
2244 err = dom_text_get_whole_text(n, &str);
2245 if (err != DOM_NO_ERR)
2246 return err;
2247
2248 err = dom_characterdata_append_data(p, str);
2249 if (err != DOM_NO_ERR)
2250 return err;
2251
2252 dom_string_unref(str);
2253
2254 return DOM_NO_ERR;
2255 }
2256
2257 /**
2258 * Try to destroy this node.
2259 *
2260 * \param node The node to destroy
2261 *
2262 * When some node owns this node, (such as an elment owns its attribute nodes)
2263 * when this node being not owned, the owner should call this function to try
2264 * to destroy this node.
2265 *
2266 * @note: Owning a node does not means this node's refcnt is above zero.
2267 */
_dom_node_try_destroy(dom_node_internal * node)2268 dom_exception _dom_node_try_destroy(dom_node_internal *node)
2269 {
2270 if (node == NULL)
2271 return DOM_NO_ERR;
2272
2273 if (node->parent == NULL) {
2274 if (node->base.refcnt == 0) {
2275 dom_node_destroy(node);
2276 } else if (node->pending_list.prev == &node->pending_list){
2277 assert (node->pending_list.next == &node->pending_list);
2278 list_append(&node->owner->pending_nodes,
2279 &node->pending_list);
2280 }
2281 }
2282
2283 return DOM_NO_ERR;
2284 }
2285
2286 /**
2287 * To add some node to the pending list, when a node is removed from its parent
2288 * or an attribute is removed from its element
2289 *
2290 * \param node The Node instance
2291 */
_dom_node_mark_pending(dom_node_internal * node)2292 void _dom_node_mark_pending(dom_node_internal *node)
2293 {
2294 struct dom_document *doc = node->owner;
2295
2296 /* TODO: the pending_list is located at in dom_document, but some
2297 * nodes can be created without a document created, such as a
2298 * dom_document_type node. For this reason, we should test whether
2299 * the doc is NULL. */
2300 if (doc != NULL) {
2301 /* The node must not be in the pending list */
2302 assert(node->pending_list.prev == &node->pending_list);
2303
2304 list_append(&doc->pending_nodes, &node->pending_list);
2305 }
2306 }
2307
2308 /**
2309 * To remove the node from the pending list, this may happen when
2310 * a node is removed and then appended to another parent
2311 *
2312 * \param node The Node instance
2313 */
_dom_node_remove_pending(dom_node_internal * node)2314 void _dom_node_remove_pending(dom_node_internal *node)
2315 {
2316 struct dom_document *doc = node->owner;
2317
2318 if (doc != NULL) {
2319 /* The node must be in the pending list */
2320 assert(node->pending_list.prev != &node->pending_list);
2321
2322 list_del(&node->pending_list);
2323 }
2324 }
2325
2326 /******************************************************************************
2327 * Event Target API *
2328 ******************************************************************************/
2329
_dom_node_add_event_listener(dom_event_target * et,dom_string * type,struct dom_event_listener * listener,bool capture)2330 dom_exception _dom_node_add_event_listener(dom_event_target *et,
2331 dom_string *type, struct dom_event_listener *listener,
2332 bool capture)
2333 {
2334 dom_node_internal *node = (dom_node_internal *) et;
2335
2336 return _dom_event_target_add_event_listener(&node->eti, type,
2337 listener, capture);
2338 }
2339
_dom_node_remove_event_listener(dom_event_target * et,dom_string * type,struct dom_event_listener * listener,bool capture)2340 dom_exception _dom_node_remove_event_listener(dom_event_target *et,
2341 dom_string *type, struct dom_event_listener *listener,
2342 bool capture)
2343 {
2344 dom_node_internal *node = (dom_node_internal *) et;
2345
2346 return _dom_event_target_remove_event_listener(&node->eti,
2347 type, listener, capture);
2348 }
2349
_dom_node_add_event_listener_ns(dom_event_target * et,dom_string * namespace,dom_string * type,struct dom_event_listener * listener,bool capture)2350 dom_exception _dom_node_add_event_listener_ns(dom_event_target *et,
2351 dom_string *namespace, dom_string *type,
2352 struct dom_event_listener *listener, bool capture)
2353 {
2354 dom_node_internal *node = (dom_node_internal *) et;
2355
2356 return _dom_event_target_add_event_listener_ns(&node->eti,
2357 namespace, type, listener, capture);
2358 }
2359
_dom_node_remove_event_listener_ns(dom_event_target * et,dom_string * namespace,dom_string * type,struct dom_event_listener * listener,bool capture)2360 dom_exception _dom_node_remove_event_listener_ns(dom_event_target *et,
2361 dom_string *namespace, dom_string *type,
2362 struct dom_event_listener *listener, bool capture)
2363 {
2364 dom_node_internal *node = (dom_node_internal *) et;
2365
2366 return _dom_event_target_remove_event_listener_ns(&node->eti,
2367 namespace, type, listener, capture);
2368 }
2369
2370
2371 /** Helper for allocating/expanding array of event targets */
_dom_event_targets_expand(uint32_t * ntargets_allocated,dom_event_target *** targets)2372 static inline dom_exception _dom_event_targets_expand(
2373 uint32_t *ntargets_allocated,
2374 dom_event_target ***targets)
2375 {
2376 dom_event_target **t = *targets;
2377 uint32_t size = *ntargets_allocated;
2378
2379 if (t == NULL) {
2380 /* Create the event target list */
2381 size = 64;
2382 t = calloc(sizeof(*t), size);
2383 if (t == NULL) {
2384 return DOM_NO_MEM_ERR;
2385 }
2386 } else {
2387 /* Extend events target list */
2388 dom_event_target **tmp = realloc(t, size * 2 * sizeof(*t));
2389 if (tmp == NULL) {
2390 return DOM_NO_MEM_ERR;
2391 }
2392 memset(tmp + size, 0, size * sizeof(*tmp));
2393 t = tmp;
2394 size *= 2;
2395 }
2396
2397 *ntargets_allocated = size;
2398 *targets = t;
2399
2400 return DOM_NO_ERR;
2401 }
2402
2403 /**
2404 * Dispatch an event into the implementation's event model
2405 *
2406 * \param et The EventTarget object
2407 * \param evt The event object
2408 * \param success Indicates whether any of the listeners which handled the
2409 * event called Event.preventDefault(). If
2410 * Event.preventDefault() was called the returned value is
2411 * false, else it is true.
2412 * \return DOM_NO_ERR on success
2413 * DOM_DISPATCH_REQUEST_ERR If the event is already in dispatch
2414 * DOM_UNSPECIFIED_EVENT_TYPE_ERR If the type of the event is Null or
2415 * empty string.
2416 * DOM_NOT_SUPPORTED_ERR If the event is not created by
2417 * Document.createEvent
2418 * DOM_INVALID_CHARACTER_ERR If the type of this event is not a
2419 * valid NCName.
2420 */
_dom_node_dispatch_event(dom_event_target * et,struct dom_event * evt,bool * success)2421 dom_exception _dom_node_dispatch_event(dom_event_target *et,
2422 struct dom_event *evt, bool *success)
2423 {
2424 dom_exception err, ret = DOM_NO_ERR;
2425 dom_node_internal *target = (dom_node_internal *) et;
2426 dom_document *doc;
2427 dom_document_event_internal *dei = NULL;
2428 dom_event_target **targets;
2429 uint32_t ntargets, ntargets_allocated, targetnr;
2430 void *pw;
2431
2432 assert(et != NULL);
2433 assert(evt != NULL);
2434
2435 /* To test whether this event is in dispatch */
2436 if (evt->in_dispatch == true) {
2437 return DOM_DISPATCH_REQUEST_ERR;
2438 } else {
2439 evt->in_dispatch = true;
2440 }
2441
2442 if (evt->type == NULL || dom_string_byte_length(evt->type) == 0) {
2443 return DOM_UNSPECIFIED_EVENT_TYPE_ERR;
2444 }
2445
2446 doc = dom_node_get_owner(et);
2447 if (doc == NULL) {
2448 /* TODO: In the progress of parsing, many Nodes in the DTD has
2449 * no document at all, do nothing for this kind of node */
2450 return DOM_NO_ERR;
2451 }
2452
2453 *success = true;
2454
2455 /* Initialise array of targets for capture/bubbling phases */
2456 targets = NULL;
2457 ntargets_allocated = 0;
2458 ntargets = 0;
2459
2460 /* Add interested event listeners to array */
2461 for (; target != NULL; target = target->parent) {
2462 struct listener_entry *le = target->eti.listeners;
2463 bool target_has_listener = false;
2464
2465 if (le == NULL) {
2466 /* This event target isn't listening to anything */
2467 continue;
2468 }
2469
2470 /* Check whether the event target is listening for this
2471 * event type */
2472 do {
2473 if (dom_string_isequal(le->type, evt->type)) {
2474 target_has_listener = true;
2475 break;
2476 }
2477 le = (struct listener_entry *) le->list.next;
2478 } while (le != target->eti.listeners);
2479
2480 if (target_has_listener == false) {
2481 continue;
2482 }
2483
2484 /* The event target is listening for this event type,
2485 * so add it to the array. */
2486 if (ntargets == ntargets_allocated) {
2487 err = _dom_event_targets_expand(&ntargets_allocated,
2488 &targets);
2489 if (err != DOM_NO_ERR) {
2490 ret = err;
2491 goto cleanup;
2492 }
2493 }
2494 targets[ntargets++] = (dom_event_target *)dom_node_ref(target);
2495 }
2496
2497 /* Fill the target of the event */
2498 evt->target = et;
2499 evt->phase = DOM_CAPTURING_PHASE;
2500
2501 /* The started callback of default action */
2502 dei = &doc->dei;
2503 pw = dei->actions_ctx;
2504 if (dei->actions != NULL) {
2505 dom_default_action_callback cb = dei->actions(evt->type,
2506 DOM_DEFAULT_ACTION_STARTED, &pw);
2507 if (cb != NULL) {
2508 cb(evt, pw);
2509 }
2510 }
2511
2512 /* The capture phase */
2513 for (targetnr = ntargets; targetnr > 0; --targetnr) {
2514 dom_node_internal *node =
2515 (dom_node_internal *) targets[targetnr - 1];
2516
2517 err = _dom_event_target_dispatch(targets[targetnr - 1],
2518 &node->eti, evt, DOM_CAPTURING_PHASE, success);
2519 if (err != DOM_NO_ERR) {
2520 ret = err;
2521 goto cleanup;
2522 }
2523 /* If the stopImmediatePropagation or stopPropagation is
2524 * called, we should break */
2525 if (evt->stop_now == true || evt->stop == true)
2526 goto cleanup;
2527 }
2528
2529 /* Target phase */
2530 evt->phase = DOM_AT_TARGET;
2531 evt->current = et;
2532 err = _dom_event_target_dispatch(et, &((dom_node_internal *) et)->eti,
2533 evt, DOM_AT_TARGET, success);
2534 if (err != DOM_NO_ERR) {
2535 ret = err;
2536 goto cleanup;
2537 }
2538 if (evt->stop_now == true || evt->stop == true)
2539 goto cleanup;
2540
2541 /* Bubbling phase */
2542 evt->phase = DOM_BUBBLING_PHASE;
2543
2544 for (targetnr = 0; targetnr < ntargets; ++targetnr) {
2545 dom_node_internal *node =
2546 (dom_node_internal *) targets[targetnr];
2547 err = _dom_event_target_dispatch(targets[targetnr],
2548 &node->eti, evt, DOM_BUBBLING_PHASE, success);
2549 if (err != DOM_NO_ERR) {
2550 ret = err;
2551 goto cleanup;
2552 }
2553 /* If the stopImmediatePropagation or stopPropagation is
2554 * called, we should break */
2555 if (evt->stop_now == true || evt->stop == true)
2556 goto cleanup;
2557 }
2558
2559 if (dei->actions == NULL)
2560 goto cleanup;
2561
2562 if (dei->actions != NULL) {
2563 dom_default_action_phase phase = DOM_DEFAULT_ACTION_END;
2564 if (evt->prevent_default == true)
2565 phase = DOM_DEFAULT_ACTION_PREVENTED;
2566 dom_default_action_callback cb = dei->actions(
2567 evt->type, phase, &pw);
2568 if (cb != NULL) {
2569 cb(evt, pw);
2570 }
2571 }
2572
2573 cleanup:
2574 if (evt->prevent_default == true) {
2575 *success = false;
2576 }
2577
2578 while (ntargets--) {
2579 dom_node_unref(targets[ntargets]);
2580 }
2581 if (targets != NULL) {
2582 free(targets);
2583 }
2584
2585 if (dei != NULL && dei->actions != NULL) {
2586 dom_default_action_callback cb = dei->actions(evt->type,
2587 DOM_DEFAULT_ACTION_FINISHED, &pw);
2588 if (cb != NULL) {
2589 cb(evt, pw);
2590 }
2591 }
2592
2593 return ret;
2594 }
2595
_dom_node_dispatch_node_change_event(dom_document * doc,dom_node_internal * node,dom_node_internal * related,dom_mutation_type change,bool * success)2596 dom_exception _dom_node_dispatch_node_change_event(dom_document *doc,
2597 dom_node_internal *node, dom_node_internal *related,
2598 dom_mutation_type change, bool *success)
2599 {
2600 dom_node_internal *target;
2601 dom_exception err;
2602
2603 /* Fire change event at immediate target */
2604 err = _dom_dispatch_node_change_event(doc, node, related,
2605 change, success);
2606 if (err != DOM_NO_ERR)
2607 return err;
2608
2609 /* Fire document change event at subtree */
2610 target = node->first_child;
2611 while (target != NULL) {
2612 err = _dom_dispatch_node_change_document_event(doc, target,
2613 change, success);
2614 if (err != DOM_NO_ERR)
2615 return err;
2616
2617 if (target->first_child != NULL) {
2618 target = target->first_child;
2619 } else if (target->next != NULL) {
2620 target = target->next;
2621 } else {
2622 dom_node_internal *parent = target->parent;
2623
2624 while (parent != node && target == parent->last_child) {
2625 target = parent;
2626 parent = target->parent;
2627 }
2628
2629 target = target->next;
2630 }
2631 }
2632
2633 return DOM_NO_ERR;
2634 }
2635
2636