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