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 <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 
14 #include <libwapcaplet/libwapcaplet.h>
15 
16 #include <dom/dom.h>
17 #include <dom/core/attr.h>
18 #include <dom/core/element.h>
19 #include <dom/core/node.h>
20 #include <dom/core/string.h>
21 #include <dom/core/document.h>
22 #include <dom/events/events.h>
23 
24 #include "core/attr.h"
25 #include "core/document.h"
26 #include "core/element.h"
27 #include "core/node.h"
28 #include "core/namednodemap.h"
29 #include "utils/validate.h"
30 #include "utils/namespace.h"
31 #include "utils/utils.h"
32 #include "utils/list.h"
33 #include "events/mutation_event.h"
34 
35 struct dom_element_vtable _dom_element_vtable = {
36 	{
37 		{
38 			DOM_NODE_EVENT_TARGET_VTABLE
39 		},
40 		DOM_NODE_VTABLE_ELEMENT
41 	},
42 	DOM_ELEMENT_VTABLE
43 };
44 
45 static struct dom_element_protected_vtable element_protect_vtable = {
46 	{
47 		DOM_NODE_PROTECT_VTABLE_ELEMENT
48 	},
49 	DOM_ELEMENT_PROTECT_VTABLE
50 };
51 
52 
53 typedef struct dom_attr_list {
54 	struct list_entry list; /**< Linked list links to prev/next entries */
55 
56 	struct dom_attr *attr;
57 
58 	struct dom_string *name;
59 	struct dom_string *namespace;
60 } dom_attr_list;
61 
62 
63 /**
64  * Destroy element's class cache
65  *
66  * \param ele  The element
67  */
_dom_element_destroy_classes(struct dom_element * ele)68 static void _dom_element_destroy_classes(struct dom_element *ele)
69 {
70 	/* Destroy the pre-separated class names */
71 	if (ele->classes != NULL) {
72 		unsigned int class;
73 		for (class = 0; class < ele->n_classes; class++) {
74 			lwc_string_unref(ele->classes[class]);
75 		}
76 		free(ele->classes);
77 	}
78 
79 	ele->n_classes = 0;
80 	ele->classes = NULL;
81 }
82 
83 
84 /**
85  * Create element's class cache from class attribute value
86  *
87  * \param ele    The element
88  * \param value  The class attribute value
89  *
90  * Destroys any existing cached classes.
91  */
_dom_element_create_classes(struct dom_element * ele,const char * value)92 static dom_exception _dom_element_create_classes(struct dom_element *ele,
93 		const char *value)
94 {
95 	const char *pos;
96 	lwc_string **classes = NULL;
97 	uint32_t n_classes = 0;
98 
99 	/* Any existing cached classes are replaced; destroy them */
100 	_dom_element_destroy_classes(ele);
101 
102 	/* Count number of classes */
103 	for (pos = value; *pos != '\0'; ) {
104 		if (*pos != ' ') {
105 			while (*pos != ' ' && *pos != '\0')
106 				pos++;
107 			n_classes++;
108 		} else {
109 			while (*pos == ' ')
110 				pos++;
111 		}
112 	}
113 
114 	/* If there are some, unpack them */
115 	if (n_classes > 0) {
116 		classes = malloc(n_classes * sizeof(lwc_string *));
117 		if (classes == NULL)
118 			return DOM_NO_MEM_ERR;
119 
120 		for (pos = value, n_classes = 0;
121 				*pos != '\0'; ) {
122 			if (*pos != ' ') {
123 				const char *s = pos;
124 				while (*pos != ' ' && *pos != '\0')
125 					pos++;
126 				if (lwc_intern_string(s, pos - s,
127 						&classes[n_classes++]) !=
128 						lwc_error_ok)
129 					goto error;
130 			} else {
131 				while (*pos == ' ')
132 					pos++;
133 			}
134 		}
135 	}
136 
137 	ele->n_classes = n_classes;
138 	ele->classes = classes;
139 
140 	return DOM_NO_ERR;
141 error:
142 	while (n_classes > 0)
143 		lwc_string_unref(classes[--n_classes]);
144 
145 	free(classes);
146 
147 	return DOM_NO_MEM_ERR;
148 }
149 
150 /* Attribute linked list releated functions */
151 
152 /**
153  * Get the next attribute in the list
154  *
155  * \param n  The attribute list node
156  * \return The next attribute node
157  */
_dom_element_attr_list_next(const dom_attr_list * n)158 static dom_attr_list * _dom_element_attr_list_next(const dom_attr_list *n)
159 {
160 	return (dom_attr_list *)(n->list.next);
161 }
162 
163 /**
164  * Unlink an attribute list node from its linked list
165  *
166  * \param n  The attribute list node
167  */
_dom_element_attr_list_node_unlink(dom_attr_list * n)168 static void _dom_element_attr_list_node_unlink(dom_attr_list *n)
169 {
170 	if (n == NULL)
171 		return;
172 
173 	list_del(&n->list);
174 }
175 
176 /**
177  * Insert attribute list node into attribute list
178  *
179  * \param list      The list header
180  * \param new_attr  The attribute node to insert
181  */
_dom_element_attr_list_insert(dom_attr_list * list,dom_attr_list * new_attr)182 static void _dom_element_attr_list_insert(dom_attr_list *list,
183 		dom_attr_list *new_attr)
184 {
185 	assert(list != NULL);
186 	assert(new_attr != NULL);
187 	list_append(&list->list, &new_attr->list);
188 }
189 
190 /**
191  * Get attribute from attribute list, which matches given name
192  *
193  * \param list  The attribute list to search
194  * \param name  The name of the attribute to search for
195  * \param name  The namespace of the attribute to search for (may be NULL)
196  * \return the matching attribute, or NULL if none found
197  */
_dom_element_attr_list_find_by_name(dom_attr_list * list,dom_string * name,dom_string * namespace)198 static dom_attr_list * _dom_element_attr_list_find_by_name(
199 		dom_attr_list *list, dom_string *name, dom_string *namespace)
200 {
201 	dom_attr_list *attr = list;
202 
203 	if (list == NULL || name == NULL)
204 		return NULL;
205 
206 	do {
207 		if (((namespace == NULL && attr->namespace == NULL) ||
208 				(namespace != NULL && attr->namespace != NULL &&
209 						dom_string_isequal(namespace,
210 						attr->namespace))) &&
211 				dom_string_isequal(name, attr->name)) {
212 			/* Both have NULL namespace or matching namespace,
213 			 * and both have same name */
214 			return attr;
215 		}
216 
217 		attr = _dom_element_attr_list_next(attr);
218 		assert(attr != NULL);
219 	} while (attr != list);
220 
221 	return NULL;
222 }
223 
224 /**
225  * Get the number of elements in this attribute list
226  *
227  * \param list  The attribute list
228  * \return the number attribute list node elements
229  */
_dom_element_attr_list_length(dom_attr_list * list)230 static unsigned int _dom_element_attr_list_length(dom_attr_list *list)
231 {
232 	dom_attr_list *attr = list;
233 	unsigned int count = 0;
234 
235 	if (list == NULL)
236 		return count;
237 
238 	do {
239 		count++;
240 
241 		attr = _dom_element_attr_list_next(attr);
242 	} while (attr != list);
243 
244 	return count;
245 }
246 
247 /**
248  * Get the attribute list node at the given index
249  *
250  * \param list   The attribute list
251  * \param index  The index number
252  * \return the attribute list node at given index
253  */
_dom_element_attr_list_get_by_index(dom_attr_list * list,unsigned int index)254 static dom_attr_list * _dom_element_attr_list_get_by_index(dom_attr_list *list,
255 		unsigned int index)
256 {
257 	dom_attr_list *attr = list;
258 
259 	if (list == NULL)
260 		return NULL;
261 
262 	do {
263 		if (--index == 0)
264 			return attr;
265 
266 		attr = _dom_element_attr_list_next(attr);
267 	} while (attr != list);
268 
269 	return NULL;
270 }
271 
272 /**
273  * Destroy an attribute list node, and its attribute
274  *
275  * \param n  The attribute list node to destroy
276  */
_dom_element_attr_list_node_destroy(dom_attr_list * n)277 static void _dom_element_attr_list_node_destroy(dom_attr_list *n)
278 {
279 	dom_node_internal *a;
280 	dom_document *doc;
281 
282 	assert(n != NULL);
283 	assert(n->attr != NULL);
284 	assert(n->name != NULL);
285 
286 	a = (dom_node_internal *) n->attr;
287 
288 	/* Need to destroy classes cache, when removing class attribute */
289 	doc = a->owner;
290 	if (n->namespace == NULL &&
291 			dom_string_isequal(n->name, doc->class_string)) {
292 		_dom_element_destroy_classes((dom_element *)(a->parent));
293 	}
294 
295 	/* Destroy rest of list node */
296 	dom_string_unref(n->name);
297 
298 	if (n->namespace != NULL)
299 		dom_string_unref(n->namespace);
300 
301 	a->parent = NULL;
302 	dom_node_try_destroy(a);
303 
304 	free(n);
305 }
306 
307 /**
308  * Create an attribute list node
309  *
310  * \param attr       The attribute to create a list node for
311  * \param name       The attribute name
312  * \param namespace  The attribute namespace (may be NULL)
313  * \return the new attribute list node, or NULL on failure
314  */
_dom_element_attr_list_node_create(dom_attr * attr,dom_element * ele,dom_string * name,dom_string * namespace)315 static dom_attr_list * _dom_element_attr_list_node_create(dom_attr *attr,
316 		dom_element *ele, dom_string *name, dom_string *namespace)
317 {
318 	dom_attr_list *new_list_node;
319 	dom_node_internal *a;
320 	dom_document *doc;
321 
322 	if (attr == NULL || name == NULL)
323 		return NULL;
324 
325 	new_list_node = malloc(sizeof(*new_list_node));
326 	if (new_list_node == NULL)
327 		return NULL;
328 
329 	list_init(&new_list_node->list);
330 
331 	new_list_node->attr = attr;
332 	new_list_node->name = name;
333 	new_list_node->namespace = namespace;
334 
335 	a = (dom_node_internal *) attr;
336 	doc = a->owner;
337 	if (namespace == NULL &&
338 			dom_string_isequal(name, doc->class_string)) {
339 		dom_string *value;
340 
341 		if (DOM_NO_ERR != _dom_attr_get_value(attr, &value)) {
342 			_dom_element_attr_list_node_destroy(new_list_node);
343 			return NULL;
344 		}
345 
346 		if (DOM_NO_ERR != _dom_element_create_classes(ele,
347 				dom_string_data(value))) {
348 			_dom_element_attr_list_node_destroy(new_list_node);
349 			dom_string_unref(value);
350 			return NULL;
351 		}
352 
353 		dom_string_unref(value);
354 	}
355 
356 	return new_list_node;
357 }
358 
359 /**
360  * Destroy an entire attribute list, and its attributes
361  *
362  * \param list  The attribute list to destroy
363  */
_dom_element_attr_list_destroy(dom_attr_list * list)364 static void _dom_element_attr_list_destroy(dom_attr_list *list)
365 {
366 	dom_attr_list *attr = list;
367 	dom_attr_list *next = list;
368 
369 	if (list == NULL)
370 		return;
371 
372 	do {
373 		attr = next;
374 		next = _dom_element_attr_list_next(attr);
375 
376 		_dom_element_attr_list_node_unlink(attr);
377 		_dom_element_attr_list_node_destroy(attr);
378 	} while (next != attr);
379 
380 	return;
381 }
382 
383 /**
384  * Clone an attribute list node, and its attribute
385  *
386  * \param n     The attribute list node to clone
387  * \param newe  Element to clone attribute for
388  * \return the new attribute list node, or NULL on failure
389  */
_dom_element_attr_list_node_clone(dom_attr_list * n,dom_element * newe)390 static dom_attr_list *_dom_element_attr_list_node_clone(dom_attr_list *n,
391 		dom_element *newe)
392 {
393 	dom_attr *clone = NULL;
394 	dom_attr_list *new_list_node;
395 	dom_exception err;
396 
397 	assert(n != NULL);
398 	assert(n->attr != NULL);
399 	assert(n->name != NULL);
400 
401 	new_list_node = malloc(sizeof(*new_list_node));
402 	if (new_list_node == NULL)
403 		return NULL;
404 
405 	list_init(&new_list_node->list);
406 
407 	new_list_node->name = NULL;
408 	new_list_node->namespace = NULL;
409 
410 	err = dom_node_clone_node(n->attr, true, (void *) &clone);
411 	if (err != DOM_NO_ERR) {
412 		free(new_list_node);
413 		return NULL;
414 	}
415 
416 	dom_node_set_parent(clone, newe);
417 	dom_node_remove_pending(clone);
418 	dom_node_unref(clone);
419 	new_list_node->attr = clone;
420 
421 	if (n->name != NULL)
422 		new_list_node->name = dom_string_ref(n->name);
423 
424 	if (n->namespace != NULL)
425 		new_list_node->namespace = dom_string_ref(n->namespace);
426 
427 	return new_list_node;
428 }
429 
430 /**
431  * Clone an entire attribute list, and its attributes
432  *
433  * \param list  The attribute list to clone
434  * \param newe  Element to clone list for
435  * \return the new attribute list, or NULL on failure
436  */
_dom_element_attr_list_clone(dom_attr_list * list,dom_element * newe)437 static dom_attr_list *_dom_element_attr_list_clone(dom_attr_list *list,
438 		dom_element *newe)
439 {
440 	dom_attr_list *attr = list;
441 
442 	dom_attr_list *new_list = NULL;
443 	dom_attr_list *new_list_node = NULL;
444 
445 	if (list == NULL)
446 		return NULL;
447 
448 	do {
449 		new_list_node = _dom_element_attr_list_node_clone(attr, newe);
450 		if (new_list_node == NULL) {
451 			if (new_list != NULL)
452 				_dom_element_attr_list_destroy(new_list);
453 			return NULL;
454 		}
455 
456 		if (new_list == NULL) {
457 			new_list = new_list_node;
458 		} else {
459 			_dom_element_attr_list_insert(new_list, new_list_node);
460 		}
461 
462 		attr = _dom_element_attr_list_next(attr);
463 	} while (attr != list);
464 
465 	return new_list;
466 }
467 
468 static dom_exception _dom_element_get_attr(struct dom_element *element,
469 		dom_string *namespace, dom_string *name, dom_string **value);
470 static dom_exception _dom_element_set_attr(struct dom_element *element,
471 		dom_string *namespace, dom_string *name, dom_string *value);
472 static dom_exception _dom_element_remove_attr(struct dom_element *element,
473 		dom_string *namespace, dom_string *name);
474 
475 static dom_exception _dom_element_get_attr_node(struct dom_element *element,
476 		dom_string *namespace, dom_string *name,
477 		struct dom_attr **result);
478 static dom_exception _dom_element_set_attr_node(struct dom_element *element,
479 		dom_string *namespace, struct dom_attr *attr,
480 		struct dom_attr **result);
481 static dom_exception _dom_element_remove_attr_node(struct dom_element *element,
482 		dom_string *namespace, struct dom_attr *attr,
483 		struct dom_attr **result);
484 
485 static dom_exception _dom_element_has_attr(struct dom_element *element,
486 		dom_string *namespace, dom_string *name, bool *result);
487 static dom_exception _dom_element_set_id_attr(struct dom_element *element,
488 		dom_string *namespace, dom_string *name, bool is_id);
489 
490 
491 /* The operation set for namednodemap */
492 static dom_exception attributes_get_length(void *priv,
493 		uint32_t *length);
494 static dom_exception attributes_get_named_item(void *priv,
495 		dom_string *name, struct dom_node **node);
496 static dom_exception attributes_set_named_item(void *priv,
497 		struct dom_node *arg, struct dom_node **node);
498 static dom_exception attributes_remove_named_item(
499 		void *priv, dom_string *name,
500 		struct dom_node **node);
501 static dom_exception attributes_item(void *priv,
502 		uint32_t index, struct dom_node **node);
503 static dom_exception attributes_get_named_item_ns(
504 		void *priv, dom_string *namespace,
505 		dom_string *localname, struct dom_node **node);
506 static dom_exception attributes_set_named_item_ns(
507 		void *priv, struct dom_node *arg,
508 		struct dom_node **node);
509 static dom_exception attributes_remove_named_item_ns(
510 		void *priv, dom_string *namespace,
511 		dom_string *localname, struct dom_node **node);
512 static void attributes_destroy(void *priv);
513 static bool attributes_equal(void *p1, void *p2);
514 
515 static struct nnm_operation attributes_opt = {
516 	attributes_get_length,
517 	attributes_get_named_item,
518 	attributes_set_named_item,
519 	attributes_remove_named_item,
520 	attributes_item,
521 	attributes_get_named_item_ns,
522 	attributes_set_named_item_ns,
523 	attributes_remove_named_item_ns,
524 	attributes_destroy,
525 	attributes_equal
526 };
527 
528 /*----------------------------------------------------------------------*/
529 /* Constructors and Destructors */
530 
531 /**
532  * Create an element node
533  *
534  * \param doc        The owning document
535  * \param name       The (local) name of the node to create
536  * \param namespace  The namespace URI of the element, or NULL
537  * \param prefix     The namespace prefix of the element, or NULL
538  * \param result     Pointer to location to receive created element
539  * \return DOM_NO_ERR                on success,
540  *         DOM_INVALID_CHARACTER_ERR if ::name is invalid,
541  *         DOM_NO_MEM_ERR            on memory exhaustion.
542  *
543  * ::doc, ::name, ::namespace and ::prefix will have their
544  * reference counts increased.
545  *
546  * The returned element will already be referenced.
547  */
_dom_element_create(struct dom_document * doc,dom_string * name,dom_string * namespace,dom_string * prefix,struct dom_element ** result)548 dom_exception _dom_element_create(struct dom_document *doc,
549 		dom_string *name, dom_string *namespace,
550 		dom_string *prefix, struct dom_element **result)
551 {
552 	/* Allocate the element */
553 	*result = malloc(sizeof(struct dom_element));
554 	if (*result == NULL)
555 		return DOM_NO_MEM_ERR;
556 
557 	/* Initialise the vtables */
558 	(*result)->base.base.vtable = &_dom_element_vtable;
559 	(*result)->base.vtable = &element_protect_vtable;
560 
561 	return _dom_element_initialise(doc, *result, name, namespace, prefix);
562 }
563 
564 /**
565  * Initialise an element node
566  *
567  * \param doc        The owning document
568  * \param el	     The element
569  * \param name       The (local) name of the node to create
570  * \param namespace  The namespace URI of the element, or NULL
571  * \param prefix     The namespace prefix of the element, or NULL
572  * \return DOM_NO_ERR                on success,
573  *         DOM_INVALID_CHARACTER_ERR if ::name is invalid,
574  *         DOM_NO_MEM_ERR            on memory exhaustion.
575  *
576  * The caller should make sure that ::name is a valid NCName.
577  *
578  * ::doc, ::name, ::namespace and ::prefix will have their
579  * reference counts increased.
580  *
581  * The returned element will already be referenced.
582  */
_dom_element_initialise(struct dom_document * doc,struct dom_element * el,dom_string * name,dom_string * namespace,dom_string * prefix)583 dom_exception _dom_element_initialise(struct dom_document *doc,
584 		struct dom_element *el, dom_string *name,
585 		dom_string *namespace, dom_string *prefix)
586 {
587 	dom_exception err;
588 
589 	assert(doc != NULL);
590 
591 	el->attributes = NULL;
592 
593 	/* Initialise the base class */
594 	err = _dom_node_initialise(&el->base, doc, DOM_ELEMENT_NODE,
595 			name, NULL, namespace, prefix);
596 	if (err != DOM_NO_ERR) {
597 		free(el);
598 		return err;
599 	}
600 
601 	/* Perform our type-specific initialisation */
602 	el->id_ns = NULL;
603 	el->id_name = NULL;
604 	el->schema_type_info = NULL;
605 
606 	el->n_classes = 0;
607 	el->classes = NULL;
608 
609 	return DOM_NO_ERR;
610 }
611 
612 /**
613  * Finalise a dom_element
614  *
615  * \param ele  The element
616  */
_dom_element_finalise(struct dom_element * ele)617 void _dom_element_finalise(struct dom_element *ele)
618 {
619 	/* Destroy attributes attached to this node */
620 	if (ele->attributes != NULL) {
621 		_dom_element_attr_list_destroy(ele->attributes);
622 		ele->attributes = NULL;
623 	}
624 
625 	if (ele->schema_type_info != NULL) {
626 		/** \todo destroy schema type info */
627 	}
628 
629 	/* Destroy the pre-separated class names */
630 	_dom_element_destroy_classes(ele);
631 
632 	/* Finalise base class */
633 	_dom_node_finalise(&ele->base);
634 }
635 
636 /**
637  * Destroy an element
638  *
639  * \param element  The element to destroy
640  *
641  * The contents of ::element will be destroyed and ::element will be freed.
642  */
_dom_element_destroy(struct dom_element * element)643 void _dom_element_destroy(struct dom_element *element)
644 {
645 	_dom_element_finalise(element);
646 
647 	/* Free the element */
648 	free(element);
649 }
650 
651 /*----------------------------------------------------------------------*/
652 
653 /* The public virtual functions */
654 
655 /**
656  * Retrieve an element's tag name
657  *
658  * \param element  The element to retrieve the name from
659  * \param name     Pointer to location to receive name
660  * \return DOM_NO_ERR      on success,
661  *         DOM_NO_MEM_ERR  on memory exhaustion.
662  *
663  * The returned string will have its reference count increased. It is
664  * the responsibility of the caller to unref the string once it has
665  * finished with it.
666  */
_dom_element_get_tag_name(struct dom_element * element,dom_string ** name)667 dom_exception _dom_element_get_tag_name(struct dom_element *element,
668 		dom_string **name)
669 {
670 	/* This is the same as nodeName */
671 	return dom_node_get_node_name((struct dom_node *) element, name);
672 }
673 
674 /**
675  * Retrieve an attribute from an element by name
676  *
677  * \param element  The element to retrieve attribute from
678  * \param name     The attribute's name
679  * \param value    Pointer to location to receive attribute's value
680  * \return DOM_NO_ERR.
681  *
682  * The returned string will have its reference count increased. It is
683  * the responsibility of the caller to unref the string once it has
684  * finished with it.
685  */
_dom_element_get_attribute(struct dom_element * element,dom_string * name,dom_string ** value)686 dom_exception _dom_element_get_attribute(struct dom_element *element,
687 		dom_string *name, dom_string **value)
688 {
689 	return _dom_element_get_attr(element, NULL, name, value);
690 }
691 
692 /**
693  * Set an attribute on an element by name
694  *
695  * \param element  The element to set attribute on
696  * \param name     The attribute's name
697  * \param value    The attribute's value
698  * \return DOM_NO_ERR                      on success,
699  *         DOM_INVALID_CHARACTER_ERR       if ::name is invalid,
700  *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly.
701  */
_dom_element_set_attribute(struct dom_element * element,dom_string * name,dom_string * value)702 dom_exception _dom_element_set_attribute(struct dom_element *element,
703 		dom_string *name, dom_string *value)
704 {
705 	return _dom_element_set_attr(element, NULL, name, value);
706 }
707 
708 /**
709  * Remove an attribute from an element by name
710  *
711  * \param element  The element to remove attribute from
712  * \param name     The name of the attribute to remove
713  * \return DOM_NO_ERR                      on success,
714  *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly.
715  */
_dom_element_remove_attribute(struct dom_element * element,dom_string * name)716 dom_exception _dom_element_remove_attribute(struct dom_element *element,
717 		dom_string *name)
718 {
719 	return _dom_element_remove_attr(element, NULL, name);
720 }
721 
722 /**
723  * Retrieve an attribute node from an element by name
724  *
725  * \param element  The element to retrieve attribute node from
726  * \param name     The attribute's name
727  * \param result   Pointer to location to receive attribute node
728  * \return DOM_NO_ERR.
729  *
730  * The returned node will have its reference count increased. It is
731  * the responsibility of the caller to unref the node once it has
732  * finished with it.
733  */
_dom_element_get_attribute_node(struct dom_element * element,dom_string * name,struct dom_attr ** result)734 dom_exception _dom_element_get_attribute_node(struct dom_element *element,
735 		dom_string *name, struct dom_attr **result)
736 {
737 	return _dom_element_get_attr_node(element, NULL, name, result);
738 }
739 
740 /**
741  * Set an attribute node on an element, replacing existing node, if present
742  *
743  * \param element  The element to add a node to
744  * \param attr     The attribute node to add
745  * \param result   Pointer to location to receive previous node
746  * \return DOM_NO_ERR                      on success,
747  *         DOM_WRONG_DOCUMENT_ERR          if ::attr does not belong to the
748  *                                         same document as ::element,
749  *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
750  *         DOM_INUSE_ATTRIBUTE_ERR         if ::attr is already an attribute
751  *                                         of another Element node.
752  *
753  * The returned node will have its reference count increased. It is
754  * the responsibility of the caller to unref the node once it has
755  * finished with it.
756  */
_dom_element_set_attribute_node(struct dom_element * element,struct dom_attr * attr,struct dom_attr ** result)757 dom_exception _dom_element_set_attribute_node(struct dom_element *element,
758 		struct dom_attr *attr, struct dom_attr **result)
759 {
760 	return _dom_element_set_attr_node(element, NULL, attr, result);
761 }
762 
763 /**
764  * Remove an attribute node from an element
765  *
766  * \param element  The element to remove attribute node from
767  * \param attr     The attribute node to remove
768  * \param result   Pointer to location to receive attribute node
769  * \return DOM_NO_ERR                      on success,
770  *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
771  *         DOM_NOT_FOUND_ERR               if ::attr is not an attribute of
772  *                                         ::element.
773  *
774  * The returned node will have its reference count increased. It is
775  * the responsibility of the caller to unref the node once it has
776  * finished with it.
777  */
_dom_element_remove_attribute_node(struct dom_element * element,struct dom_attr * attr,struct dom_attr ** result)778 dom_exception _dom_element_remove_attribute_node(struct dom_element *element,
779 		struct dom_attr *attr, struct dom_attr **result)
780 {
781 	return _dom_element_remove_attr_node(element, NULL, attr, result);
782 }
783 
784 /**
785  * Retrieve a list of descendant elements of an element which match a given
786  * tag name
787  *
788  * \param element  The root of the subtree to search
789  * \param name     The tag name to match (or "*" for all tags)
790  * \param result   Pointer to location to receive result
791  * \return DOM_NO_ERR.
792  *
793  * The returned nodelist will have its reference count increased. It is
794  * the responsibility of the caller to unref the nodelist once it has
795  * finished with it.
796  */
_dom_element_get_elements_by_tag_name(struct dom_element * element,dom_string * name,struct dom_nodelist ** result)797 dom_exception _dom_element_get_elements_by_tag_name(
798 		struct dom_element *element, dom_string *name,
799 		struct dom_nodelist **result)
800 {
801 	dom_exception err;
802 	dom_node_internal *base = (dom_node_internal *) element;
803 
804 	assert(base->owner != NULL);
805 
806 	err = _dom_document_get_nodelist(base->owner, DOM_NODELIST_BY_NAME,
807 			(struct dom_node_internal *) element, name, NULL,
808 			NULL, result);
809 
810 	return err;
811 }
812 
813 /**
814  * Retrieve an attribute from an element by namespace/localname
815  *
816  * \param element    The element to retrieve attribute from
817  * \param namespace  The attribute's namespace URI, or NULL
818  * \param localname  The attribute's local name
819  * \param value      Pointer to location to receive attribute's value
820  * \return DOM_NO_ERR            on success,
821  *         DOM_NOT_SUPPORTED_ERR if the implementation does not support
822  *                               the feature "XML" and the language exposed
823  *                               through the Document does not support
824  *                               Namespaces.
825  *
826  * The returned string will have its reference count increased. It is
827  * the responsibility of the caller to unref the string once it has
828  * finished with it.
829  */
_dom_element_get_attribute_ns(struct dom_element * element,dom_string * namespace,dom_string * localname,dom_string ** value)830 dom_exception _dom_element_get_attribute_ns(struct dom_element *element,
831 		dom_string *namespace, dom_string *localname,
832 		dom_string **value)
833 {
834 	return _dom_element_get_attr(element, namespace, localname, value);
835 }
836 
837 /**
838  * Set an attribute on an element by namespace/qualified name
839  *
840  * \param element    The element to set attribute on
841  * \param namespace  The attribute's namespace URI
842  * \param qname      The attribute's qualified name
843  * \param value      The attribute's value
844  * \return DOM_NO_ERR                      on success,
845  *         DOM_INVALID_CHARACTER_ERR       if ::qname is invalid,
846  *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
847  *         DOM_NAMESPACE_ERR               if ::qname is malformed, or
848  *                                         ::qname has a prefix and
849  *                                         ::namespace is null, or ::qname
850  *                                         has a prefix "xml" and
851  *                                         ::namespace is not
852  *                                         "http://www.w3.org/XML/1998/namespace",
853  *                                         or ::qname has a prefix "xmlns"
854  *                                         and ::namespace is not
855  *                                         "http://www.w3.org/2000/xmlns",
856  *                                         or ::namespace is
857  *                                         "http://www.w3.org/2000/xmlns"
858  *                                         and ::qname is not prefixed
859  *                                         "xmlns",
860  *         DOM_NOT_SUPPORTED_ERR           if the implementation does not
861  *                                         support the feature "XML" and the
862  *                                         language exposed through the
863  *                                         Document does not support
864  *                                         Namespaces.
865  */
_dom_element_set_attribute_ns(struct dom_element * element,dom_string * namespace,dom_string * qname,dom_string * value)866 dom_exception _dom_element_set_attribute_ns(struct dom_element *element,
867 		dom_string *namespace, dom_string *qname,
868 		dom_string *value)
869 {
870 	dom_exception err;
871 	dom_string *localname;
872 	dom_string *prefix;
873 
874 	if (_dom_validate_name(qname) == false)
875 		return DOM_INVALID_CHARACTER_ERR;
876 
877 	err = _dom_namespace_validate_qname(qname, namespace);
878 	if (err != DOM_NO_ERR)
879 		return DOM_NAMESPACE_ERR;
880 
881 	err = _dom_namespace_split_qname(qname, &prefix, &localname);
882 	if (err != DOM_NO_ERR)
883 		return err;
884 
885 	/* If there is no namespace, must have a prefix */
886 	if (namespace == NULL && prefix != NULL) {
887 		dom_string_unref(prefix);
888 		dom_string_unref(localname);
889 		return DOM_NAMESPACE_ERR;
890 	}
891 
892 	err = _dom_element_set_attr(element, namespace, localname, value);
893 
894 	dom_string_unref(prefix);
895 	dom_string_unref(localname);
896 
897 	return err;
898 }
899 
900 /**
901  * Remove an attribute from an element by namespace/localname
902  *
903  * \param element    The element to remove attribute from
904  * \param namespace  The attribute's namespace URI
905  * \param localname  The attribute's local name
906  * \return DOM_NO_ERR                      on success,
907  *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
908  *         DOM_NOT_SUPPORTED_ERR           if the implementation does not
909  *                                         support the feature "XML" and the
910  *                                         language exposed through the
911  *                                         Document does not support
912  *                                         Namespaces.
913  */
_dom_element_remove_attribute_ns(struct dom_element * element,dom_string * namespace,dom_string * localname)914 dom_exception _dom_element_remove_attribute_ns(struct dom_element *element,
915 		dom_string *namespace, dom_string *localname)
916 {
917 	return _dom_element_remove_attr(element, namespace, localname);
918 }
919 
920 /**
921  * Retrieve an attribute node from an element by namespace/localname
922  *
923  * \param element    The element to retrieve attribute from
924  * \param namespace  The attribute's namespace URI
925  * \param localname  The attribute's local name
926  * \param result     Pointer to location to receive attribute node
927  * \return DOM_NO_ERR            on success,
928  *         DOM_NOT_SUPPORTED_ERR if the implementation does not support
929  *                               the feature "XML" and the language exposed
930  *                               through the Document does not support
931  *                               Namespaces.
932  *
933  * The returned node will have its reference count increased. It is
934  * the responsibility of the caller to unref the node once it has
935  * finished with it.
936  */
_dom_element_get_attribute_node_ns(struct dom_element * element,dom_string * namespace,dom_string * localname,struct dom_attr ** result)937 dom_exception _dom_element_get_attribute_node_ns(struct dom_element *element,
938 		dom_string *namespace, dom_string *localname,
939 		struct dom_attr **result)
940 {
941 	return _dom_element_get_attr_node(element, namespace, localname,
942 			result);
943 }
944 
945 /**
946  * Set an attribute node on an element, replacing existing node, if present
947  *
948  * \param element  The element to add a node to
949  * \param attr     The attribute node to add
950  * \param result   Pointer to location to recieve previous node
951  * \return DOM_NO_ERR                      on success,
952  *         DOM_WRONG_DOCUMENT_ERR          if ::attr does not belong to the
953  *                                         same document as ::element,
954  *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
955  *         DOM_INUSE_ATTRIBUTE_ERR         if ::attr is already an attribute
956  *                                         of another Element node.
957  *         DOM_NOT_SUPPORTED_ERR           if the implementation does not
958  *                                         support the feature "XML" and the
959  *                                         language exposed through the
960  *                                         Document does not support
961  *                                         Namespaces.
962  *
963  * The returned node will have its reference count increased. It is
964  * the responsibility of the caller to unref the node once it has
965  * finished with it.
966  */
_dom_element_set_attribute_node_ns(struct dom_element * element,struct dom_attr * attr,struct dom_attr ** result)967 dom_exception _dom_element_set_attribute_node_ns(struct dom_element *element,
968 		struct dom_attr *attr, struct dom_attr **result)
969 {
970 	dom_exception err;
971 	dom_string *namespace;
972 
973 	err = dom_node_get_namespace(attr, (void *) &namespace);
974 	if (err != DOM_NO_ERR)
975 		return err;
976 
977 	err = _dom_element_set_attr_node(element, namespace, attr, result);
978 
979 	if (namespace != NULL)
980 		dom_string_unref(namespace);
981 
982 	return err;
983 }
984 
985 /**
986  * Retrieve a list of descendant elements of an element which match a given
987  * namespace/localname pair.
988  *
989  * \param element  The root of the subtree to search
990  * \param namespace  The namespace URI to match (or "*" for all)
991  * \param localname  The local name to match (or "*" for all)
992  * \param result   Pointer to location to receive result
993  * \return DOM_NO_ERR            on success,
994  *         DOM_NOT_SUPPORTED_ERR if the implementation does not support
995  *                               the feature "XML" and the language exposed
996  *                               through the Document does not support
997  *                               Namespaces.
998  *
999  * The returned nodelist will have its reference count increased. It is
1000  * the responsibility of the caller to unref the nodelist once it has
1001  * finished with it.
1002  */
_dom_element_get_elements_by_tag_name_ns(struct dom_element * element,dom_string * namespace,dom_string * localname,struct dom_nodelist ** result)1003 dom_exception _dom_element_get_elements_by_tag_name_ns(
1004 		struct dom_element *element, dom_string *namespace,
1005 		dom_string *localname, struct dom_nodelist **result)
1006 {
1007 	dom_exception err;
1008 
1009 	/** \todo ensure XML feature is supported */
1010 
1011 	err = _dom_document_get_nodelist(element->base.owner,
1012 			DOM_NODELIST_BY_NAMESPACE,
1013 			(struct dom_node_internal *) element, NULL,
1014 			namespace, localname,
1015 			result);
1016 
1017 	return err;
1018 }
1019 
1020 /**
1021  * Determine if an element possesses and attribute with the given name
1022  *
1023  * \param element  The element to query
1024  * \param name     The attribute name to look for
1025  * \param result   Pointer to location to receive result
1026  * \return DOM_NO_ERR.
1027  */
_dom_element_has_attribute(struct dom_element * element,dom_string * name,bool * result)1028 dom_exception _dom_element_has_attribute(struct dom_element *element,
1029 		dom_string *name, bool *result)
1030 {
1031 	return _dom_element_has_attr(element, NULL, name, result);
1032 }
1033 
1034 /**
1035  * Determine if an element possesses and attribute with the given
1036  * namespace/localname pair.
1037  *
1038  * \param element    The element to query
1039  * \param namespace  The attribute namespace URI to look for
1040  * \param localname  The attribute local name to look for
1041  * \param result   Pointer to location to receive result
1042  * \return DOM_NO_ERR            on success,
1043  *         DOM_NOT_SUPPORTED_ERR if the implementation does not support
1044  *                               the feature "XML" and the language exposed
1045  *                               through the Document does not support
1046  *                               Namespaces.
1047  */
_dom_element_has_attribute_ns(struct dom_element * element,dom_string * namespace,dom_string * localname,bool * result)1048 dom_exception _dom_element_has_attribute_ns(struct dom_element *element,
1049 		dom_string *namespace, dom_string *localname,
1050 		bool *result)
1051 {
1052 	return _dom_element_has_attr(element, namespace, localname, result);
1053 }
1054 
1055 /**
1056  * Retrieve the type information associated with an element
1057  *
1058  * \param element  The element to retrieve type information from
1059  * \param result   Pointer to location to receive type information
1060  * \return DOM_NO_ERR.
1061  *
1062  * The returned typeinfo will have its reference count increased. It is
1063  * the responsibility of the caller to unref the typeinfo once it has
1064  * finished with it.
1065  */
_dom_element_get_schema_type_info(struct dom_element * element,struct dom_type_info ** result)1066 dom_exception _dom_element_get_schema_type_info(struct dom_element *element,
1067 		struct dom_type_info **result)
1068 {
1069 	UNUSED(element);
1070 	UNUSED(result);
1071 
1072 	return DOM_NOT_SUPPORTED_ERR;
1073 }
1074 
1075 /**
1076  * (Un)declare an attribute as being an element's ID by name
1077  *
1078  * \param element  The element containing the attribute
1079  * \param name     The attribute's name
1080  * \param is_id    Whether the attribute is an ID
1081  * \return DOM_NO_ERR                      on success,
1082  *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
1083  *         DOM_NOT_FOUND_ERR               if the specified node is not an
1084  *                                         attribute of ::element.
1085  *
1086  * @note: The DOM spec does not say: how to deal with when there are two or
1087  * more isId attribute nodes. Here, the implementation just maintain only
1088  * one such attribute node.
1089  */
_dom_element_set_id_attribute(struct dom_element * element,dom_string * name,bool is_id)1090 dom_exception _dom_element_set_id_attribute(struct dom_element *element,
1091 		dom_string *name, bool is_id)
1092 {
1093 	return _dom_element_set_id_attr(element, NULL, name, is_id);
1094 }
1095 
1096 /**
1097  * (Un)declare an attribute as being an element's ID by namespace/localname
1098  *
1099  * \param element    The element containing the attribute
1100  * \param namespace  The attribute's namespace URI
1101  * \param localname  The attribute's local name
1102  * \param is_id      Whether the attribute is an ID
1103  * \return DOM_NO_ERR                      on success,
1104  *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
1105  *         DOM_NOT_FOUND_ERR               if the specified node is not an
1106  *                                         attribute of ::element.
1107  */
_dom_element_set_id_attribute_ns(struct dom_element * element,dom_string * namespace,dom_string * localname,bool is_id)1108 dom_exception _dom_element_set_id_attribute_ns(struct dom_element *element,
1109 		dom_string *namespace, dom_string *localname,
1110 		bool is_id)
1111 {
1112 	dom_exception err;
1113 
1114 	err = _dom_element_set_id_attr(element, namespace, localname, is_id);
1115 
1116 	element->id_ns = dom_string_ref(namespace);
1117 
1118 	return err;
1119 }
1120 
1121 /**
1122  * (Un)declare an attribute node as being an element's ID
1123  *
1124  * \param element  The element containing the attribute
1125  * \param id_attr  The attribute node
1126  * \param is_id    Whether the attribute is an ID
1127  * \return DOM_NO_ERR                      on success,
1128  *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
1129  *         DOM_NOT_FOUND_ERR               if the specified node is not an
1130  *                                         attribute of ::element.
1131  */
_dom_element_set_id_attribute_node(struct dom_element * element,struct dom_attr * id_attr,bool is_id)1132 dom_exception _dom_element_set_id_attribute_node(struct dom_element *element,
1133 		struct dom_attr *id_attr, bool is_id)
1134 {
1135 	dom_exception err;
1136 	dom_string *namespace;
1137 	dom_string *localname;
1138 
1139 	err = dom_node_get_namespace(id_attr, &namespace);
1140 	if (err != DOM_NO_ERR)
1141 		return err;
1142 	err = dom_node_get_local_name(id_attr, &localname);
1143 	if (err != DOM_NO_ERR)
1144 		return err;
1145 
1146 	err = _dom_element_set_id_attr(element, namespace, localname, is_id);
1147 	if (err != DOM_NO_ERR)
1148 		return err;
1149 
1150 	element->id_ns = namespace;
1151 
1152 	return DOM_NO_ERR;
1153 
1154 }
1155 
1156 /**
1157  * Obtain a pre-parsed array of class names for an element
1158  *
1159  * \param element    Element containing classes
1160  * \param classes    Pointer to location to receive libdom-owned array
1161  * \param n_classes  Pointer to location to receive number of classes
1162  * \return DOM_NO_ERR on success,
1163  *         DOM_NO_MEM_ERR on memory exhaustion
1164  */
_dom_element_get_classes(struct dom_element * element,lwc_string *** classes,uint32_t * n_classes)1165 dom_exception _dom_element_get_classes(struct dom_element *element,
1166 		lwc_string ***classes, uint32_t *n_classes)
1167 {
1168 	if (element->n_classes > 0) {
1169 		uint32_t classnr;
1170 
1171 		*classes = element->classes;
1172 		*n_classes = element->n_classes;
1173 
1174 		for (classnr = 0; classnr < element->n_classes; classnr++)
1175 			(void) lwc_string_ref((*classes)[classnr]);
1176 
1177 	} else {
1178 		*n_classes = 0;
1179 		*classes = NULL;
1180 	}
1181 
1182 	return DOM_NO_ERR;
1183 }
1184 
1185 /**
1186  * Determine if an element has an associated class
1187  *
1188  * \param element  Element to consider
1189  * \param name     Class name to look for
1190  * \param match    Pointer to location to receive result
1191  * \return DOM_NO_ERR.
1192  */
_dom_element_has_class(struct dom_element * element,lwc_string * name,bool * match)1193 dom_exception _dom_element_has_class(struct dom_element *element,
1194 		lwc_string *name, bool *match)
1195 {
1196 	dom_exception err;
1197 	unsigned int class;
1198 	struct dom_node_internal *node = (struct dom_node_internal *)element;
1199 	dom_document_quirks_mode quirks_mode;
1200 
1201 	/* Short-circuit case where we have no classes */
1202 	if (element->n_classes == 0) {
1203 		*match = false;
1204 		return DOM_NO_ERR;
1205 	}
1206 
1207 	err = dom_document_get_quirks_mode(node->owner, &quirks_mode);
1208 	if (err != DOM_NO_ERR)
1209 		return err;
1210 
1211 	if (quirks_mode != DOM_DOCUMENT_QUIRKS_MODE_NONE) {
1212 		/* Quirks mode: case insensitively match */
1213 		for (class = 0; class < element->n_classes; class++) {
1214 			if (lwc_error_ok == lwc_string_caseless_isequal(name,
1215 					element->classes[class], match) &&
1216 					*match == true)
1217 				return DOM_NO_ERR;
1218 		}
1219 	} else {
1220 		/* Standards mode: case sensitively match */
1221 		for (class = 0; class < element->n_classes; class++) {
1222 			if (lwc_error_ok == lwc_string_isequal(name,
1223 					element->classes[class], match) &&
1224 					*match == true)
1225 				return DOM_NO_ERR;
1226 		}
1227 	}
1228 
1229 	return DOM_NO_ERR;
1230 }
1231 
1232 /**
1233  * Get a named ancestor node
1234  *
1235  * \param element   Element to consider
1236  * \param name      Node name to look for
1237  * \param ancestor  Pointer to location to receive node pointer
1238  * \return DOM_NO_ERR.
1239  */
dom_element_named_ancestor_node(dom_element * element,lwc_string * name,dom_element ** ancestor)1240 dom_exception dom_element_named_ancestor_node(dom_element *element,
1241 		lwc_string *name, dom_element **ancestor)
1242 {
1243 	dom_node_internal *node = (dom_node_internal *)element;
1244 
1245 	*ancestor = NULL;
1246 
1247 	for (node = node->parent; node != NULL; node = node->parent) {
1248 		if (node->type != DOM_ELEMENT_NODE)
1249 			continue;
1250 
1251 		assert(node->name != NULL);
1252 
1253 		if (dom_string_caseless_lwc_isequal(node->name, name)) {
1254 			*ancestor = (dom_element *)node;
1255 			break;
1256 		}
1257 	}
1258 
1259 	return DOM_NO_ERR;
1260 }
1261 
1262 /**
1263  * Get a named parent node
1264  *
1265  * \param element  Element to consider
1266  * \param name     Node name to look for
1267  * \param parent   Pointer to location to receive node pointer
1268  * \return DOM_NO_ERR.
1269  */
dom_element_named_parent_node(dom_element * element,lwc_string * name,dom_element ** parent)1270 dom_exception dom_element_named_parent_node(dom_element *element,
1271 		lwc_string *name, dom_element **parent)
1272 {
1273 	dom_node_internal *node = (dom_node_internal *)element;
1274 
1275 	*parent = NULL;
1276 
1277 	for (node = node->parent; node != NULL; node = node->parent) {
1278 		if (node->type != DOM_ELEMENT_NODE)
1279 			continue;
1280 
1281 		assert(node->name != NULL);
1282 
1283 		if (dom_string_caseless_lwc_isequal(node->name, name)) {
1284 			*parent = (dom_element *)node;
1285 		}
1286 		break;
1287 	}
1288 
1289 	return DOM_NO_ERR;
1290 }
1291 
1292 /**
1293  * Get a named parent node
1294  *
1295  * \param element  Element to consider
1296  * \param name     Node name to look for
1297  * \param parent   Pointer to location to receive node pointer
1298  * \return DOM_NO_ERR.
1299  */
dom_element_parent_node(dom_element * element,dom_element ** parent)1300 dom_exception dom_element_parent_node(dom_element *element,
1301 		dom_element **parent)
1302 {
1303 	dom_node_internal *node = (dom_node_internal *)element;
1304 
1305 	*parent = NULL;
1306 
1307 	for (node = node->parent; node != NULL; node = node->parent) {
1308 		if (node->type != DOM_ELEMENT_NODE)
1309 			continue;
1310 
1311 		*parent = (dom_element *)node;
1312 		break;
1313 	}
1314 
1315 	return DOM_NO_ERR;
1316 }
1317 
1318 /*------------- The overload virtual functions ------------------------*/
1319 
1320 /* Overload function of Node, please refer src/core/node.c for detail */
_dom_element_get_attributes(dom_node_internal * node,struct dom_namednodemap ** result)1321 dom_exception _dom_element_get_attributes(dom_node_internal *node,
1322 		struct dom_namednodemap **result)
1323 {
1324 	dom_exception err;
1325 	dom_document *doc;
1326 
1327 	doc = dom_node_get_owner(node);
1328 	assert(doc != NULL);
1329 
1330 	err = _dom_namednodemap_create(doc, node, &attributes_opt, result);
1331 	if (err != DOM_NO_ERR)
1332 		return err;
1333 
1334 	dom_node_ref(node);
1335 
1336 	return DOM_NO_ERR;
1337 }
1338 
1339 /* Overload function of Node, please refer src/core/node.c for detail */
_dom_element_has_attributes(dom_node_internal * node,bool * result)1340 dom_exception _dom_element_has_attributes(dom_node_internal *node, bool *result)
1341 {
1342 	UNUSED(node);
1343 	*result = true;
1344 
1345 	return DOM_NO_ERR;
1346 }
1347 
1348 /* For the following namespace related algorithm take a look at:
1349  * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/namespaces-algorithms.html
1350  */
1351 
1352 /**
1353  * Look up the prefix which matches the namespace.
1354  *
1355  * \param node       The current Node in which we search for
1356  * \param namespace  The namespace for which we search a prefix
1357  * \param result     The returned prefix
1358  * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
1359  */
_dom_element_lookup_prefix(dom_node_internal * node,dom_string * namespace,dom_string ** result)1360 dom_exception _dom_element_lookup_prefix(dom_node_internal *node,
1361 		dom_string *namespace, dom_string **result)
1362 {
1363 	struct dom_element *owner;
1364 	dom_exception err;
1365 
1366 	err = dom_attr_get_owner_element(node, &owner);
1367 	if (err != DOM_NO_ERR)
1368 		return err;
1369 
1370 	if (owner == NULL) {
1371 		*result = NULL;
1372 		return DOM_NO_ERR;
1373 	}
1374 
1375 	return dom_node_lookup_prefix(owner, namespace, result);
1376 }
1377 
1378 /**
1379  * Test whether certain namespace is the default namespace of some node.
1380  *
1381  * \param node       The Node to test
1382  * \param namespace  The namespace to test
1383  * \param result     true is the namespace is default namespace
1384  * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
1385  */
_dom_element_is_default_namespace(dom_node_internal * node,dom_string * namespace,bool * result)1386 dom_exception _dom_element_is_default_namespace(dom_node_internal *node,
1387 		dom_string *namespace, bool *result)
1388 {
1389 	struct dom_element *ele = (struct dom_element *) node;
1390 	dom_string *value;
1391 	dom_exception err;
1392 	bool has;
1393 	dom_string *xmlns;
1394 
1395 	if (node->prefix == NULL) {
1396 		*result = dom_string_isequal(node->namespace, namespace);
1397 		return DOM_NO_ERR;
1398 	}
1399 
1400 	xmlns = _dom_namespace_get_xmlns_prefix();
1401 	err = dom_element_has_attribute(ele, xmlns, &has);
1402 	if (err != DOM_NO_ERR)
1403 		return err;
1404 
1405 	if (has == true) {
1406 		err = dom_element_get_attribute(ele, xmlns, &value);
1407 		if (err != DOM_NO_ERR)
1408 			return err;
1409 
1410 		*result = dom_string_isequal(value, namespace);
1411 
1412 		dom_string_unref(value);
1413 
1414 		return DOM_NO_ERR;
1415 	}
1416 
1417 	return dom_node_is_default_namespace(node->parent, namespace, result);
1418 }
1419 
1420 /**
1421  * Look up the namespace with certain prefix.
1422  *
1423  * \param node    The current node in which we search for the prefix
1424  * \param prefix  The prefix to search
1425  * \param result  The result namespace if found
1426  * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
1427  */
_dom_element_lookup_namespace(dom_node_internal * node,dom_string * prefix,dom_string ** result)1428 dom_exception _dom_element_lookup_namespace(dom_node_internal *node,
1429 		dom_string *prefix, dom_string **result)
1430 {
1431 	dom_exception err;
1432 	bool has;
1433 	dom_string *xmlns;
1434 
1435 	if (node->namespace != NULL &&
1436 			dom_string_isequal(node->prefix, prefix)) {
1437 		*result = dom_string_ref(node->namespace);
1438 		return DOM_NO_ERR;
1439 	}
1440 
1441 	xmlns = _dom_namespace_get_xmlns_prefix();
1442 	err = dom_element_has_attribute_ns(node, xmlns, prefix, &has);
1443 	if (err != DOM_NO_ERR)
1444 		return err;
1445 
1446 	if (has == true)
1447 		return dom_element_get_attribute_ns(node,
1448 				dom_namespaces[DOM_NAMESPACE_XMLNS], prefix,
1449 				result);
1450 
1451 	err = dom_element_has_attribute(node, xmlns, &has);
1452 	if (err != DOM_NO_ERR)
1453 		return err;
1454 
1455 	if (has == true) {
1456 		return dom_element_get_attribute(node, xmlns, result);
1457 	}
1458 
1459 	return dom_node_lookup_namespace(node->parent, prefix, result);
1460 }
1461 
1462 
1463 /*----------------------------------------------------------------------*/
1464 /* The protected virtual functions */
1465 
1466 /**
1467  * The virtual function to parse some dom attribute
1468  *
1469  * \param ele     The element object
1470  * \param name    The name of the attribute
1471  * \param value   The new value of the attribute
1472  * \param parsed  The parsed value of the attribute
1473  * \return DOM_NO_ERR on success.
1474  *
1475  * @note: This virtual method is provided to serve as a template method.
1476  * When any attribute is set or added, the attribute's value should be
1477  * checked to make sure that it is a valid one. And the child class of
1478  * dom_element may to do some special stuff on the attribute is set. Take
1479  * some integer attribute as example:
1480  *
1481  * 1. The client call dom_element_set_attribute("size", "10.1"), but the
1482  *    size attribute may only accept an integer, and only the specific
1483  *    dom_element know this. And the dom_attr_set_value method, which is
1484  *    called by dom_element_set_attribute should call the this virtual
1485  *    template method.
1486  * 2. The overload virtual function of following one will truncate the
1487  *    "10.1" to "10" to make sure it is a integer. And of course, the
1488  *    overload method may also save the integer as a 'int' C type for
1489  *    later easy accessing by any client.
1490  */
_dom_element_parse_attribute(dom_element * ele,dom_string * name,dom_string * value,dom_string ** parsed)1491 dom_exception _dom_element_parse_attribute(dom_element *ele,
1492 		dom_string *name, dom_string *value,
1493 		dom_string **parsed)
1494 {
1495 	UNUSED(ele);
1496 	UNUSED(name);
1497 
1498 	dom_string_ref(value);
1499 	*parsed = value;
1500 
1501 	return DOM_NO_ERR;
1502 }
1503 
1504 /* The destroy virtual function of dom_element */
__dom_element_destroy(struct dom_node_internal * node)1505 void __dom_element_destroy(struct dom_node_internal *node)
1506 {
1507 	_dom_element_destroy((struct dom_element *) node);
1508 }
1509 
1510 /* TODO: How to deal with default attribue:
1511  *
1512  *  Ask a language binding for default attributes.
1513  *
1514  *	So, when we copy a element we copy all its attributes because they
1515  *	are all specified. For the methods like importNode and adoptNode,
1516  *	this will make _dom_element_copy can be used in them.
1517  */
_dom_element_copy(dom_node_internal * old,dom_node_internal ** copy)1518 dom_exception _dom_element_copy(dom_node_internal *old,
1519 		dom_node_internal **copy)
1520 {
1521 	dom_element *new_node;
1522 	dom_exception err;
1523 
1524 	new_node = malloc(sizeof(dom_element));
1525 	if (new_node == NULL)
1526 		return DOM_NO_MEM_ERR;
1527 
1528 	err = dom_element_copy_internal(old, new_node);
1529 	if (err != DOM_NO_ERR) {
1530 		free(new_node);
1531 		return err;
1532 	}
1533 
1534 	*copy = (dom_node_internal *) new_node;
1535 
1536 	return DOM_NO_ERR;
1537 }
1538 
_dom_element_copy_internal(dom_element * old,dom_element * new)1539 dom_exception _dom_element_copy_internal(dom_element *old, dom_element *new)
1540 {
1541 	dom_exception err;
1542 	uint32_t classnr;
1543 
1544 	if (old->attributes != NULL) {
1545 		/* Copy the attribute list */
1546 		new->attributes = _dom_element_attr_list_clone(
1547 				old->attributes, new);
1548 	} else {
1549 		new->attributes = NULL;
1550 	}
1551 
1552 	if (old->n_classes > 0) {
1553 		new->n_classes = old->n_classes;
1554 		new->classes = malloc(sizeof(lwc_string *) * new->n_classes);
1555 		if (new->classes == NULL) {
1556 			err = DOM_NO_MEM_ERR;
1557 			goto error;
1558 		}
1559 		for (classnr = 0; classnr < new->n_classes; ++classnr)
1560 			new->classes[classnr] =
1561 				lwc_string_ref(old->classes[classnr]);
1562 	} else {
1563 		new->n_classes = 0;
1564 		new->classes = NULL;
1565 	}
1566 
1567 	err = dom_node_copy_internal(old, new);
1568 	if (err != DOM_NO_ERR) {
1569 		goto error;
1570 	}
1571 
1572 	new->id_ns = NULL;
1573 	new->id_name = NULL;
1574 
1575 	/* TODO: deal with dom_type_info, it get no definition ! */
1576 
1577 	return DOM_NO_ERR;
1578 
1579 error:
1580 	free(new->classes);
1581 	return err;
1582 }
1583 
1584 
1585 
1586 /*--------------------------------------------------------------------------*/
1587 
1588 /* Helper functions */
1589 
1590 /**
1591  * The internal helper function for getAttribute/getAttributeNS.
1592  *
1593  * \param element    The element
1594  * \param namespace  The namespace to look for attribute in.  May be NULL.
1595  * \param name       The name of the attribute
1596  * \param value      The value of the attribute
1597  * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
1598  */
_dom_element_get_attr(struct dom_element * element,dom_string * namespace,dom_string * name,dom_string ** value)1599 dom_exception _dom_element_get_attr(struct dom_element *element,
1600 		dom_string *namespace, dom_string *name, dom_string **value)
1601 {
1602 	dom_attr_list *match;
1603 	dom_exception err = DOM_NO_ERR;
1604 
1605 	match = _dom_element_attr_list_find_by_name(element->attributes,
1606 			name, namespace);
1607 
1608 	/* Fill in value */
1609 	if (match == NULL) {
1610 		*value = NULL;
1611 	} else {
1612 		err = dom_attr_get_value(match->attr, value);
1613 	}
1614 
1615 	return err;
1616 }
1617 
1618 /**
1619  * The internal helper function for setAttribute and setAttributeNS.
1620  *
1621  * \param element    The element
1622  * \param namespace  The namespace to set attribute for.  May be NULL.
1623  * \param name       The name of the new attribute
1624  * \param value      The value of the new attribute
1625  * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
1626  */
_dom_element_set_attr(struct dom_element * element,dom_string * namespace,dom_string * name,dom_string * value)1627 dom_exception _dom_element_set_attr(struct dom_element *element,
1628 		dom_string *namespace, dom_string *name, dom_string *value)
1629 {
1630 	dom_attr_list *match;
1631 	dom_node_internal *e = (dom_node_internal *) element;
1632 	dom_exception err;
1633 
1634 	if (_dom_validate_name(name) == false)
1635 		return DOM_INVALID_CHARACTER_ERR;
1636 
1637 	/* Ensure element can be written */
1638 	if (_dom_node_readonly(e))
1639 		return DOM_NO_MODIFICATION_ALLOWED_ERR;
1640 
1641 	match = _dom_element_attr_list_find_by_name(element->attributes,
1642 			name, namespace);
1643 
1644 	if (match != NULL) {
1645 		/* Found an existing attribute, so replace its value */
1646 
1647 		/* Dispatch a DOMAttrModified event */
1648 		dom_string *old = NULL;
1649 		struct dom_document *doc = dom_node_get_owner(element);
1650 		bool success = true;
1651 		err = dom_attr_get_value(match->attr, &old);
1652 		/* TODO: We did not support some node type such as entity
1653 		 * reference, in that case, we should ignore the error to
1654 		 * make sure the event model work as excepted. */
1655 		if (err != DOM_NO_ERR && err != DOM_NOT_SUPPORTED_ERR)
1656 			return err;
1657 		err = _dom_dispatch_attr_modified_event(doc, e, old, value,
1658 				match->attr, name, DOM_MUTATION_MODIFICATION,
1659 				&success);
1660 		dom_string_unref(old);
1661 		if (err != DOM_NO_ERR)
1662 			return err;
1663 
1664 		err = dom_attr_set_value(match->attr, value);
1665 		if (err != DOM_NO_ERR)
1666 			return err;
1667 
1668 		success = true;
1669 		err = _dom_dispatch_subtree_modified_event(doc,
1670 				(dom_event_target *) e, &success);
1671 		if (err != DOM_NO_ERR)
1672 			return err;
1673 	} else {
1674 		/* No existing attribute, so create one */
1675 		struct dom_attr *attr;
1676 		struct dom_attr_list *list_node;
1677 		struct dom_document *doc;
1678 		bool success = true;
1679 
1680 		err = _dom_attr_create(e->owner, name, namespace, NULL,
1681 				true, &attr);
1682 		if (err != DOM_NO_ERR)
1683 			return err;
1684 
1685 		/* Set its parent, so that value parsing works */
1686 		dom_node_set_parent(attr, element);
1687 
1688 		/* Set its value */
1689 		err = dom_attr_set_value(attr, value);
1690 		if (err != DOM_NO_ERR) {
1691 			dom_node_set_parent(attr, NULL);
1692 			dom_node_unref(attr);
1693 			return err;
1694 		}
1695 
1696 		/* Dispatch a DOMAttrModified event */
1697 		doc = dom_node_get_owner(element);
1698 		err = _dom_dispatch_attr_modified_event(doc, e, NULL, value,
1699 				(dom_event_target *) attr, name,
1700 				DOM_MUTATION_ADDITION, &success);
1701 		if (err != DOM_NO_ERR) {
1702 			dom_node_set_parent(attr, NULL);
1703 			dom_node_unref(attr);
1704 			return err;
1705 		}
1706 
1707 		err = dom_node_dispatch_node_change_event(doc,
1708 				attr, element, DOM_MUTATION_ADDITION, &success);
1709 		if (err != DOM_NO_ERR) {
1710 			dom_node_set_parent(attr, NULL);
1711 			dom_node_unref(attr);
1712 			return err;
1713 		}
1714 
1715 		/* Create attribute list node */
1716 		list_node = _dom_element_attr_list_node_create(attr, element,
1717 				name, namespace);
1718 		if (list_node == NULL) {
1719 			/* If we failed at this step, there must be no memory */
1720 			dom_node_set_parent(attr, NULL);
1721 			dom_node_unref(attr);
1722 			return DOM_NO_MEM_ERR;
1723 		}
1724 		dom_string_ref(name);
1725 		dom_string_ref(namespace);
1726 
1727 		/* Link into element's attribute list */
1728 		if (element->attributes == NULL)
1729 			element->attributes = list_node;
1730 		else
1731 			_dom_element_attr_list_insert(element->attributes,
1732 					list_node);
1733 
1734 		dom_node_unref(attr);
1735 		dom_node_remove_pending(attr);
1736 
1737 		success = true;
1738 		err = _dom_dispatch_subtree_modified_event(doc,
1739 				(dom_event_target *) element, &success);
1740 		if (err != DOM_NO_ERR)
1741 			return err;
1742 	}
1743 
1744 	return DOM_NO_ERR;
1745 }
1746 
1747 /**
1748  * Remove an attribute from an element by name
1749  *
1750  * \param element  The element to remove attribute from
1751  * \param name     The name of the attribute to remove
1752  * \return DOM_NO_ERR                      on success,
1753  *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly.
1754  */
_dom_element_remove_attr(struct dom_element * element,dom_string * namespace,dom_string * name)1755 dom_exception _dom_element_remove_attr(struct dom_element *element,
1756 		dom_string *namespace, dom_string *name)
1757 {
1758 	dom_attr_list *match;
1759 	dom_exception err;
1760 	dom_node_internal *e = (dom_node_internal *) element;
1761 
1762 	/* Ensure element can be written to */
1763 	if (_dom_node_readonly(e))
1764 		return DOM_NO_MODIFICATION_ALLOWED_ERR;
1765 
1766 	match = _dom_element_attr_list_find_by_name(element->attributes,
1767 			name, namespace);
1768 
1769 	/* Detach attr node from list */
1770 	if (match != NULL) {
1771 		/* Disptach DOMNodeRemoval event */
1772 		bool success = true;
1773 		dom_attr *a = match->attr;
1774 		struct dom_document *doc = dom_node_get_owner(element);
1775 		dom_string *old = NULL;
1776 
1777 		err = dom_node_dispatch_node_change_event(doc, match->attr,
1778 				element, DOM_MUTATION_REMOVAL, &success);
1779 		if (err != DOM_NO_ERR)
1780 			return err;
1781 
1782 		/* Claim a reference for later event dispatch */
1783 		dom_node_ref(a);
1784 
1785 
1786 		/* Delete the attribute node */
1787 		if (element->attributes == match) {
1788 			element->attributes =
1789 					_dom_element_attr_list_next(match);
1790 		}
1791 		if (element->attributes == match) {
1792 			/* match must be sole attribute */
1793 			element->attributes = NULL;
1794 		}
1795 		_dom_element_attr_list_node_unlink(match);
1796 		_dom_element_attr_list_node_destroy(match);
1797 
1798 		/* Dispatch a DOMAttrModified event */
1799 		success = true;
1800 		err = dom_attr_get_value(a, &old);
1801 		/* TODO: We did not support some node type such as entity
1802 		 * reference, in that case, we should ignore the error to
1803 		 * make sure the event model work as excepted. */
1804 		if (err != DOM_NO_ERR && err != DOM_NOT_SUPPORTED_ERR)
1805 			return err;
1806 		err = _dom_dispatch_attr_modified_event(doc, e, old, NULL, a,
1807 				name, DOM_MUTATION_REMOVAL, &success);
1808 		dom_string_unref(old);
1809 		/* Release the reference */
1810 		dom_node_unref(a);
1811 		if (err != DOM_NO_ERR)
1812 			return err;
1813 
1814 		success = true;
1815 		err = _dom_dispatch_subtree_modified_event(doc,
1816 				(dom_event_target *) e, &success);
1817 		if (err != DOM_NO_ERR)
1818 			return err;
1819 	}
1820 
1821 	/** \todo defaulted attribute handling */
1822 
1823 	return DOM_NO_ERR;
1824 }
1825 
1826 /**
1827  * Retrieve an attribute node from an element by name
1828  *
1829  * \param element  The element to retrieve attribute node from
1830  * \param name     The attribute's name
1831  * \param result   Pointer to location to receive attribute node
1832  * \return DOM_NO_ERR.
1833  *
1834  * The returned node will have its reference count increased. It is
1835  * the responsibility of the caller to unref the node once it has
1836  * finished with it.
1837  */
_dom_element_get_attr_node(struct dom_element * element,dom_string * namespace,dom_string * name,struct dom_attr ** result)1838 dom_exception _dom_element_get_attr_node(struct dom_element *element,
1839 		dom_string *namespace, dom_string *name,
1840 		struct dom_attr **result)
1841 {
1842 	dom_attr_list *match;
1843 
1844 	match = _dom_element_attr_list_find_by_name(element->attributes,
1845 			name, namespace);
1846 
1847 	/* Fill in value */
1848 	if (match == NULL) {
1849 		*result = NULL;
1850 	} else {
1851 		*result = match->attr;
1852 		dom_node_ref(*result);
1853 	}
1854 
1855 	return DOM_NO_ERR;
1856 }
1857 
1858 /**
1859  * Set an attribute node on an element, replacing existing node, if present
1860  *
1861  * \param element  The element to add a node to
1862  * \param attr     The attribute node to add
1863  * \param result   Pointer to location to receive previous node
1864  * \return DOM_NO_ERR                      on success,
1865  *         DOM_WRONG_DOCUMENT_ERR          if ::attr does not belong to the
1866  *                                         same document as ::element,
1867  *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
1868  *         DOM_INUSE_ATTRIBUTE_ERR         if ::attr is already an attribute
1869  *                                         of another Element node.
1870  *
1871  * The returned node will have its reference count increased. It is
1872  * the responsibility of the caller to unref the node once it has
1873  * finished with it.
1874  */
_dom_element_set_attr_node(struct dom_element * element,dom_string * namespace,struct dom_attr * attr,struct dom_attr ** result)1875 dom_exception _dom_element_set_attr_node(struct dom_element *element,
1876 		dom_string *namespace, struct dom_attr *attr,
1877 		struct dom_attr **result)
1878 {
1879 	dom_attr_list *match;
1880 	dom_exception err;
1881 	dom_string *name = NULL;
1882 	dom_node_internal *e = (dom_node_internal *) element;
1883 	dom_node_internal *attr_node = (dom_node_internal *) attr;
1884 	dom_attr *old_attr;
1885 	dom_string *new = NULL;
1886 	struct dom_document *doc;
1887 	bool success = true;
1888 
1889 	/** \todo validate name */
1890 
1891 	/* Ensure element and attribute belong to the same document */
1892 	if (e->owner != attr_node->owner)
1893 		return DOM_WRONG_DOCUMENT_ERR;
1894 
1895 	/* Ensure element can be written to */
1896 	if (_dom_node_readonly(e))
1897 		return DOM_NO_MODIFICATION_ALLOWED_ERR;
1898 
1899 	/* Ensure attribute isn't attached to another element */
1900 	if (attr_node->parent != NULL && attr_node->parent != e)
1901 		return DOM_INUSE_ATTRIBUTE_ERR;
1902 
1903 	err = dom_node_get_local_name(attr, &name);
1904 	if (err != DOM_NO_ERR)
1905 		return err;
1906 
1907 	match = _dom_element_attr_list_find_by_name(element->attributes,
1908 			name, namespace);
1909 
1910 	*result = NULL;
1911 	if (match != NULL) {
1912 		/* Disptach DOMNodeRemoval event */
1913 		dom_string *old = NULL;
1914 		doc = dom_node_get_owner(element);
1915 		old_attr = match->attr;
1916 
1917 		err = dom_node_dispatch_node_change_event(doc, old_attr,
1918 				element, DOM_MUTATION_REMOVAL, &success);
1919 		if (err != DOM_NO_ERR) {
1920 			dom_string_unref(name);
1921 			return err;
1922 		}
1923 
1924 		dom_node_ref(old_attr);
1925 
1926 		_dom_element_attr_list_node_unlink(match);
1927 		_dom_element_attr_list_node_destroy(match);
1928 
1929 		/* Dispatch a DOMAttrModified event */
1930 		success = true;
1931 		err = dom_attr_get_value(old_attr, &old);
1932 		/* TODO: We did not support some node type such as entity
1933 		 * reference, in that case, we should ignore the error to
1934 		 * make sure the event model work as excepted. */
1935 		if (err != DOM_NO_ERR && err != DOM_NOT_SUPPORTED_ERR) {
1936 			dom_node_unref(old_attr);
1937 			dom_string_unref(name);
1938 			return err;
1939 		}
1940 		err = _dom_dispatch_attr_modified_event(doc, e, old, NULL,
1941 				(dom_event_target *) old_attr, name,
1942 				DOM_MUTATION_REMOVAL, &success);
1943 		dom_string_unref(old);
1944 		*result = old_attr;
1945 		if (err != DOM_NO_ERR) {
1946 			dom_string_unref(name);
1947 			return err;
1948 		}
1949 
1950 		success = true;
1951 		err = _dom_dispatch_subtree_modified_event(doc,
1952 				(dom_event_target *) e, &success);
1953 		if (err != DOM_NO_ERR) {
1954 			dom_string_unref(name);
1955 			return err;
1956 		}
1957 	}
1958 
1959 
1960 	match = _dom_element_attr_list_node_create(attr, element,
1961 			name, namespace);
1962 	if (match == NULL) {
1963 		dom_string_unref(name);
1964 		/* If we failed at this step, there must be no memory */
1965 		return DOM_NO_MEM_ERR;
1966 	}
1967 
1968 	dom_string_ref(name);
1969 	dom_string_ref(namespace);
1970 	dom_node_set_parent(attr, element);
1971 	dom_node_remove_pending(attr);
1972 
1973 	/* Dispatch a DOMAttrModified event */
1974 	doc = dom_node_get_owner(element);
1975 	success = true;
1976 	err = dom_attr_get_value(attr, &new);
1977 	/* TODO: We did not support some node type such as entity reference, in
1978 	 * that case, we should ignore the error to make sure the event model
1979 	 * work as excepted. */
1980 	if (err != DOM_NO_ERR && err != DOM_NOT_SUPPORTED_ERR) {
1981 		_dom_element_attr_list_node_destroy(match);
1982 		return err;
1983 	}
1984 	err = _dom_dispatch_attr_modified_event(doc, e, NULL, new,
1985 			(dom_event_target *) attr, name,
1986 			DOM_MUTATION_ADDITION, &success);
1987 	/* Cleanup */
1988 	dom_string_unref(new);
1989 	dom_string_unref(name);
1990 	if (err != DOM_NO_ERR) {
1991 		_dom_element_attr_list_node_destroy(match);
1992 		return err;
1993 	}
1994 
1995 	err = dom_node_dispatch_node_change_event(doc, attr, element,
1996 			DOM_MUTATION_ADDITION, &success);
1997 	if (err != DOM_NO_ERR) {
1998 		_dom_element_attr_list_node_destroy(match);
1999 		return err;
2000 	}
2001 
2002 	success = true;
2003 	err = _dom_dispatch_subtree_modified_event(doc,
2004 			(dom_event_target *) element, &success);
2005 	if (err != DOM_NO_ERR) {
2006 		_dom_element_attr_list_node_destroy(match);
2007 		return err;
2008 	}
2009 
2010 	/* Link into element's attribute list */
2011 	if (element->attributes == NULL)
2012 		element->attributes = match;
2013 	else
2014 		_dom_element_attr_list_insert(element->attributes, match);
2015 
2016 	return DOM_NO_ERR;
2017 }
2018 
2019 /**
2020  * Remove an attribute node from an element
2021  *
2022  * \param element  The element to remove attribute node from
2023  * \param attr     The attribute node to remove
2024  * \param result   Pointer to location to receive attribute node
2025  * \return DOM_NO_ERR                      on success,
2026  *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
2027  *         DOM_NOT_FOUND_ERR               if ::attr is not an attribute of
2028  *                                         ::element.
2029  *
2030  * The returned node will have its reference count increased. It is
2031  * the responsibility of the caller to unref the node once it has
2032  * finished with it.
2033  */
_dom_element_remove_attr_node(struct dom_element * element,dom_string * namespace,struct dom_attr * attr,struct dom_attr ** result)2034 dom_exception _dom_element_remove_attr_node(struct dom_element *element,
2035 		dom_string *namespace, struct dom_attr *attr,
2036 		struct dom_attr **result)
2037 {
2038 	dom_attr_list *match;
2039 	dom_exception err;
2040 	dom_string *name;
2041 	dom_node_internal *e = (dom_node_internal *) element;
2042 	dom_attr *a;
2043 	bool success = true;
2044 	struct dom_document *doc;
2045 	dom_string *old = NULL;
2046 
2047 	/* Ensure element can be written to */
2048 	if (_dom_node_readonly(e))
2049 		return DOM_NO_MODIFICATION_ALLOWED_ERR;
2050 
2051 	err = dom_node_get_node_name(attr, &name);
2052 	if (err != DOM_NO_ERR)
2053 		return err;
2054 
2055 	match = _dom_element_attr_list_find_by_name(element->attributes,
2056 			name, namespace);
2057 
2058 	/** \todo defaulted attribute handling */
2059 
2060 	if (match == NULL || match->attr != attr) {
2061 		dom_string_unref(name);
2062 		return DOM_NOT_FOUND_ERR;
2063 	}
2064 
2065 	a = match->attr;
2066 
2067 	/* Dispatch a DOMNodeRemoved event */
2068 	doc = dom_node_get_owner(element);
2069 	err = dom_node_dispatch_node_change_event(doc, a, element,
2070 			DOM_MUTATION_REMOVAL, &success);
2071 	if (err != DOM_NO_ERR) {
2072 		dom_string_unref(name);
2073 		return err;
2074 	}
2075 
2076 	dom_node_ref(a);
2077 
2078 	/* Delete the attribute node */
2079 	if (element->attributes == match) {
2080 		element->attributes = _dom_element_attr_list_next(match);
2081 	}
2082 	if (element->attributes == match) {
2083 		/* match must be sole attribute */
2084 		element->attributes = NULL;
2085 	}
2086 	_dom_element_attr_list_node_unlink(match);
2087 	_dom_element_attr_list_node_destroy(match);
2088 
2089 	/* Now, cleaup the dom_string */
2090 	dom_string_unref(name);
2091 
2092 	/* Dispatch a DOMAttrModified event */
2093 	success = true;
2094 	err = dom_attr_get_value(a, &old);
2095 	/* TODO: We did not support some node type such as entity reference, in
2096 	 * that case, we should ignore the error to make sure the event model
2097 	 * work as excepted. */
2098 	if (err != DOM_NO_ERR && err != DOM_NOT_SUPPORTED_ERR) {
2099 		dom_node_unref(a);
2100 		return err;
2101 	}
2102 	err = _dom_dispatch_attr_modified_event(doc, e, old, NULL,
2103 			(dom_event_target *) a, name,
2104 			DOM_MUTATION_REMOVAL, &success);
2105 	dom_string_unref(old);
2106 	if (err != DOM_NO_ERR)
2107 		return err;
2108 
2109 	/* When a Node is removed, it should be destroy. When its refcnt is not
2110 	 * zero, it will be added to the document's deletion pending list.
2111 	 * When a Node is removed, its parent should be NULL, but its owner
2112 	 * should remain to be the document.
2113 	 */
2114 	*result = (dom_attr *) a;
2115 
2116 	success = true;
2117 	err = _dom_dispatch_subtree_modified_event(doc,
2118 			(dom_event_target *) e, &success);
2119 	if (err != DOM_NO_ERR)
2120 		return err;
2121 
2122 	return DOM_NO_ERR;
2123 }
2124 
2125 /**
2126  * Test whether certain attribute exists on the element
2127  *
2128  * \param element    The element
2129  * \param namespace  The namespace to look for attribute in.  May be NULL.
2130  * \param name       The attribute's name
2131  * \param result     The return value
2132  * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
2133  */
_dom_element_has_attr(struct dom_element * element,dom_string * namespace,dom_string * name,bool * result)2134 dom_exception _dom_element_has_attr(struct dom_element *element,
2135 		dom_string *namespace, dom_string *name, bool *result)
2136 {
2137 	dom_attr_list *match;
2138 
2139 	match = _dom_element_attr_list_find_by_name(element->attributes,
2140 			name, namespace);
2141 
2142 	/* Fill in result */
2143 	if (match == NULL) {
2144 		*result = false;
2145 	} else {
2146 		*result = true;
2147 	}
2148 
2149 	return DOM_NO_ERR;
2150 }
2151 
2152 /**
2153  * (Un)set an attribute Node as a ID.
2154  *
2155  * \param element    The element contains the attribute
2156  * \param namespace  The namespace of the attribute node
2157  * \param name       The name of the attribute
2158  * \param is_id      true for set the node as a ID attribute, false unset it
2159  * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
2160  */
_dom_element_set_id_attr(struct dom_element * element,dom_string * namespace,dom_string * name,bool is_id)2161 dom_exception _dom_element_set_id_attr(struct dom_element *element,
2162 		dom_string *namespace, dom_string *name, bool is_id)
2163 {
2164 
2165 	dom_attr_list *match;
2166 
2167 	match = _dom_element_attr_list_find_by_name(element->attributes,
2168 			name, namespace);
2169 	if (match == NULL)
2170 		return DOM_NOT_FOUND_ERR;
2171 
2172 	if (is_id == true) {
2173 		/* Clear the previous id attribute if there is one */
2174 		dom_attr_list *old = _dom_element_attr_list_find_by_name(
2175 				element->attributes, element->id_name,
2176 				element->id_ns);
2177 
2178 		if (old != NULL) {
2179 			_dom_attr_set_isid(old->attr, false);
2180 		}
2181 
2182 		/* Set up the new id attr stuff */
2183 		element->id_name = dom_string_ref(name);
2184 		element->id_ns = dom_string_ref(namespace);
2185 	}
2186 
2187 	_dom_attr_set_isid(match->attr, is_id);
2188 
2189 	return DOM_NO_ERR;
2190 }
2191 
2192 /**
2193  * Get the ID string of the element
2194  *
2195  * \param ele  The element
2196  * \param id   The ID of this element
2197  * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
2198  */
_dom_element_get_id(struct dom_element * ele,dom_string ** id)2199 dom_exception _dom_element_get_id(struct dom_element *ele, dom_string **id)
2200 {
2201 	dom_exception err;
2202 	dom_string *ret = NULL;
2203 	dom_document *doc;
2204 	dom_string *name;
2205 
2206 	*id = NULL;
2207 
2208 	if (ele->id_ns != NULL && ele->id_name != NULL) {
2209 		/* There is user specific ID attribute */
2210 		err = _dom_element_get_attribute_ns(ele, ele->id_ns,
2211 				ele->id_name, &ret);
2212 		if (err != DOM_NO_ERR) {
2213 			return err;
2214 		}
2215 
2216 		*id = ret;
2217 		return err;
2218 	}
2219 
2220 	doc = dom_node_get_owner(ele);
2221 	assert(doc != NULL);
2222 
2223 	if (ele->id_name != NULL) {
2224 		name = ele->id_name;
2225 	} else {
2226 		name = _dom_document_get_id_name(doc);
2227 
2228 		if (name == NULL) {
2229 			/* No ID attribute at all, just return NULL */
2230 			*id = NULL;
2231 			return DOM_NO_ERR;
2232 		}
2233 	}
2234 
2235 	err = _dom_element_get_attribute(ele, name, &ret);
2236 	if (err != DOM_NO_ERR) {
2237 		return err;
2238 	}
2239 
2240 	if (ret != NULL) {
2241 		*id = ret;
2242 	} else {
2243 		*id = NULL;
2244 	}
2245 
2246 	return err;
2247 }
2248 
2249 
2250 
2251 /*-------------- The dom_namednodemap functions -------------------------*/
2252 
2253 /* Implementation function for NamedNodeMap, see core/namednodemap.h for
2254  * details */
attributes_get_length(void * priv,uint32_t * length)2255 dom_exception attributes_get_length(void *priv, uint32_t *length)
2256 {
2257 	dom_element *e = (dom_element *) priv;
2258 
2259 	*length = _dom_element_attr_list_length(e->attributes);
2260 
2261 	return DOM_NO_ERR;
2262 }
2263 
2264 /* Implementation function for NamedNodeMap, see core/namednodemap.h for
2265  * details */
attributes_get_named_item(void * priv,dom_string * name,struct dom_node ** node)2266 dom_exception attributes_get_named_item(void *priv,
2267 		dom_string *name, struct dom_node **node)
2268 {
2269 	dom_element *e = (dom_element *) priv;
2270 
2271 	return _dom_element_get_attribute_node(e, name, (dom_attr **) node);
2272 }
2273 
2274 /* Implementation function for NamedNodeMap, see core/namednodemap.h for
2275  * details */
attributes_set_named_item(void * priv,struct dom_node * arg,struct dom_node ** node)2276 dom_exception attributes_set_named_item(void *priv,
2277 		struct dom_node *arg, struct dom_node **node)
2278 {
2279 	dom_element *e = (dom_element *) priv;
2280 	dom_node_internal *n = (dom_node_internal *) arg;
2281 
2282 	if (n->type != DOM_ATTRIBUTE_NODE)
2283 		return DOM_HIERARCHY_REQUEST_ERR;
2284 
2285 	return _dom_element_set_attribute_node(e, (dom_attr *) arg,
2286 			(dom_attr **) node);
2287 }
2288 
2289 /* Implementation function for NamedNodeMap, see core/namednodemap.h for
2290  * details */
attributes_remove_named_item(void * priv,dom_string * name,struct dom_node ** node)2291 dom_exception attributes_remove_named_item(
2292 		void *priv, dom_string *name,
2293 		struct dom_node **node)
2294 {
2295 	dom_element *e = (dom_element *) priv;
2296 	dom_exception err;
2297 
2298 	err = _dom_element_get_attribute_node(e, name, (dom_attr **) node);
2299 	if (err != DOM_NO_ERR)
2300 		return err;
2301 
2302 	if (*node == NULL) {
2303 		return DOM_NOT_FOUND_ERR;
2304 	}
2305 
2306 	return _dom_element_remove_attribute(e, name);
2307 }
2308 
2309 /* Implementation function for NamedNodeMap, see core/namednodemap.h for
2310  * details */
attributes_item(void * priv,uint32_t index,struct dom_node ** node)2311 dom_exception attributes_item(void *priv,
2312 		uint32_t index, struct dom_node **node)
2313 {
2314 	dom_attr_list * match = NULL;
2315 	unsigned int num = index + 1;
2316 	dom_element *e = (dom_element *) priv;
2317 
2318 	match = _dom_element_attr_list_get_by_index(e->attributes, num);
2319 
2320 	if (match != NULL) {
2321 		*node = (dom_node *) match->attr;
2322 		dom_node_ref(*node);
2323 	} else {
2324 		*node = NULL;
2325 	}
2326 
2327 	return DOM_NO_ERR;
2328 }
2329 
2330 /* Implementation function for NamedNodeMap, see core/namednodemap.h for
2331  * details */
attributes_get_named_item_ns(void * priv,dom_string * namespace,dom_string * localname,struct dom_node ** node)2332 dom_exception attributes_get_named_item_ns(
2333 		void *priv, dom_string *namespace,
2334 		dom_string *localname, struct dom_node **node)
2335 {
2336 	dom_element *e = (dom_element *) priv;
2337 
2338 	return _dom_element_get_attribute_node_ns(e, namespace, localname,
2339 			(dom_attr **) node);
2340 }
2341 
2342 /* Implementation function for NamedNodeMap, see core/namednodemap.h for
2343  * details */
attributes_set_named_item_ns(void * priv,struct dom_node * arg,struct dom_node ** node)2344 dom_exception attributes_set_named_item_ns(
2345 		void *priv, struct dom_node *arg,
2346 		struct dom_node **node)
2347 {
2348 	dom_element *e = (dom_element *) priv;
2349 	dom_node_internal *n = (dom_node_internal *) arg;
2350 
2351 	if (n->type != DOM_ATTRIBUTE_NODE)
2352 		return DOM_HIERARCHY_REQUEST_ERR;
2353 
2354 	return _dom_element_set_attribute_node_ns(e, (dom_attr *) arg,
2355 			(dom_attr **) node);
2356 }
2357 
2358 /* Implementation function for NamedNodeMap, see core/namednodemap.h for
2359  * details */
attributes_remove_named_item_ns(void * priv,dom_string * namespace,dom_string * localname,struct dom_node ** node)2360 dom_exception attributes_remove_named_item_ns(
2361 		void *priv, dom_string *namespace,
2362 		dom_string *localname, struct dom_node **node)
2363 {
2364 	dom_element *e = (dom_element *) priv;
2365 	dom_exception err;
2366 
2367 	err = _dom_element_get_attribute_node_ns(e, namespace, localname,
2368 			(dom_attr **) node);
2369 	if (err != DOM_NO_ERR)
2370 		return err;
2371 
2372 	if (*node == NULL) {
2373 		return DOM_NOT_FOUND_ERR;
2374 	}
2375 
2376 	return _dom_element_remove_attribute_ns(e, namespace, localname);
2377 }
2378 
2379 /* Implementation function for NamedNodeMap, see core/namednodemap.h for
2380  * details */
attributes_destroy(void * priv)2381 void attributes_destroy(void *priv)
2382 {
2383 	dom_element *e = (dom_element *) priv;
2384 
2385 	dom_node_unref(e);
2386 }
2387 
2388 /* Implementation function for NamedNodeMap, see core/namednodemap.h for
2389  * details */
attributes_equal(void * p1,void * p2)2390 bool attributes_equal(void *p1, void *p2)
2391 {
2392 	/* We have passed the pointer to this element as the private data,
2393 	 * and here we just need to compare whether the two elements are
2394 	 * equal
2395 	 */
2396 	return p1 == p2;
2397 }
2398 /*------------------ End of namednodemap functions -----------------------*/
2399 
2400