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