1 /*
2    +----------------------------------------------------------------------+
3    | Copyright (c) The PHP Group                                          |
4    +----------------------------------------------------------------------+
5    | This source file is subject to version 3.01 of the PHP license,      |
6    | that is bundled with this package in the file LICENSE, and is        |
7    | available through the world-wide-web at the following url:           |
8    | http://www.php.net/license/3_01.txt                                  |
9    | If you did not receive a copy of the PHP license and are unable to   |
10    | obtain it through the world-wide-web, please send a note to          |
11    | license@php.net so we can mail you a copy immediately.               |
12    +----------------------------------------------------------------------+
13    | Authors: Christian Stocker <chregu@php.net>                          |
14    |          Rob Richards <rrichards@php.net>                            |
15    +----------------------------------------------------------------------+
16 */
17 
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21 
22 #include "php.h"
23 #if defined(HAVE_LIBXML) && defined(HAVE_DOM)
24 #include "php_dom.h"
25 
26 /*
27 * class DOMNode
28 *
29 * URL: https://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1950641247
30 * Since:
31 */
32 
33 /* {{{ nodeName	string
34 readonly=yes
35 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-F68D095
36 Since:
37 */
dom_node_node_name_read(dom_object * obj,zval * retval)38 int dom_node_node_name_read(dom_object *obj, zval *retval)
39 {
40 	xmlNode *nodep;
41 	xmlNsPtr ns;
42 	char *str = NULL;
43 	xmlChar *qname = NULL;
44 
45 	nodep = dom_object_get_node(obj);
46 
47 	if (nodep == NULL) {
48 		php_dom_throw_error(INVALID_STATE_ERR, 0);
49 		return FAILURE;
50 	}
51 
52 	switch (nodep->type) {
53 		case XML_ATTRIBUTE_NODE:
54 		case XML_ELEMENT_NODE:
55 			ns = nodep->ns;
56 			if (ns != NULL && ns->prefix) {
57 				qname = xmlStrdup(ns->prefix);
58 				qname = xmlStrcat(qname, (xmlChar *) ":");
59 				qname = xmlStrcat(qname, nodep->name);
60 				str = (char *) qname;
61 			} else {
62 				str = (char *) nodep->name;
63 			}
64 			break;
65 		case XML_NAMESPACE_DECL:
66 			ns = nodep->ns;
67 			if (ns != NULL && ns->prefix) {
68 				qname = xmlStrdup((xmlChar *) "xmlns");
69 				qname = xmlStrcat(qname, (xmlChar *) ":");
70 				qname = xmlStrcat(qname, nodep->name);
71 				str = (char *) qname;
72 			} else {
73 				str = (char *) nodep->name;
74 			}
75 			break;
76 		case XML_DOCUMENT_TYPE_NODE:
77 		case XML_DTD_NODE:
78 		case XML_PI_NODE:
79 		case XML_ENTITY_DECL:
80 		case XML_ENTITY_REF_NODE:
81 		case XML_NOTATION_NODE:
82 			str = (char *) nodep->name;
83 			break;
84 		case XML_CDATA_SECTION_NODE:
85 			str = "#cdata-section";
86 			break;
87 		case XML_COMMENT_NODE:
88 			str = "#comment";
89 			break;
90 		case XML_HTML_DOCUMENT_NODE:
91 		case XML_DOCUMENT_NODE:
92 			str = "#document";
93 			break;
94 		case XML_DOCUMENT_FRAG_NODE:
95 			str = "#document-fragment";
96 			break;
97 		case XML_TEXT_NODE:
98 			str = "#text";
99 			break;
100 		EMPTY_SWITCH_DEFAULT_CASE();
101 	}
102 
103 	if (str != NULL) {
104 		ZVAL_STRING(retval, str);
105 	} else {
106 		ZVAL_EMPTY_STRING(retval);
107 	}
108 
109 	if (qname != NULL) {
110 		xmlFree(qname);
111 	}
112 
113 	return SUCCESS;
114 
115 }
116 
117 /* }}} */
118 
119 /* {{{ nodeValue	string
120 readonly=no
121 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-F68D080
122 Since:
123 */
dom_node_node_value_read(dom_object * obj,zval * retval)124 int dom_node_node_value_read(dom_object *obj, zval *retval)
125 {
126 	xmlNode *nodep = dom_object_get_node(obj);
127 	char *str = NULL;
128 
129 	if (nodep == NULL) {
130 		php_dom_throw_error(INVALID_STATE_ERR, 0);
131 		return FAILURE;
132 	}
133 
134 	/* Access to Element node is implemented as a convenience method */
135 	switch (nodep->type) {
136 		case XML_ATTRIBUTE_NODE:
137 		case XML_TEXT_NODE:
138 		case XML_ELEMENT_NODE:
139 		case XML_COMMENT_NODE:
140 		case XML_CDATA_SECTION_NODE:
141 		case XML_PI_NODE:
142 			str = (char *) xmlNodeGetContent(nodep);
143 			break;
144 		case XML_NAMESPACE_DECL:
145 			str = (char *) xmlNodeGetContent(nodep->children);
146 			break;
147 		default:
148 			str = NULL;
149 			break;
150 	}
151 
152 	if(str != NULL) {
153 		ZVAL_STRING(retval, str);
154 		xmlFree(str);
155 	} else {
156 		ZVAL_NULL(retval);
157 	}
158 
159 	return SUCCESS;
160 
161 }
162 
dom_node_node_value_write(dom_object * obj,zval * newval)163 int dom_node_node_value_write(dom_object *obj, zval *newval)
164 {
165 	xmlNode *nodep = dom_object_get_node(obj);
166 	zend_string *str;
167 
168 	if (nodep == NULL) {
169 		php_dom_throw_error(INVALID_STATE_ERR, 0);
170 		return FAILURE;
171 	}
172 
173 	str = zval_try_get_string(newval);
174 	if (UNEXPECTED(!str)) {
175 		return FAILURE;
176 	}
177 
178 	/* Access to Element node is implemented as a convenience method */
179 	switch (nodep->type) {
180 		case XML_ELEMENT_NODE:
181 		case XML_ATTRIBUTE_NODE:
182 			if (nodep->children) {
183 				node_list_unlink(nodep->children);
184 				php_libxml_node_free_list((xmlNodePtr) nodep->children);
185 				nodep->children = NULL;
186 			}
187 		case XML_TEXT_NODE:
188 		case XML_COMMENT_NODE:
189 		case XML_CDATA_SECTION_NODE:
190 		case XML_PI_NODE:
191 			xmlNodeSetContentLen(nodep, (xmlChar *) ZSTR_VAL(str), ZSTR_LEN(str) + 1);
192 			break;
193 		default:
194 			break;
195 	}
196 
197 	zend_string_release_ex(str, 0);
198 	return SUCCESS;
199 }
200 
201 /* }}} */
202 
203 /* {{{ nodeType	int
204 readonly=yes
205 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-111237558
206 Since:
207 */
dom_node_node_type_read(dom_object * obj,zval * retval)208 int dom_node_node_type_read(dom_object *obj, zval *retval)
209 {
210 	xmlNode *nodep;
211 
212 	nodep = dom_object_get_node(obj);
213 
214 	if (nodep == NULL) {
215 		php_dom_throw_error(INVALID_STATE_ERR, 0);
216 		return FAILURE;
217 	}
218 
219 	/* Specs dictate that they are both type XML_DOCUMENT_TYPE_NODE */
220 	if (nodep->type == XML_DTD_NODE) {
221 		ZVAL_LONG(retval, XML_DOCUMENT_TYPE_NODE);
222 	} else {
223 		ZVAL_LONG(retval, nodep->type);
224 	}
225 
226 	return SUCCESS;
227 }
228 
229 /* }}} */
230 
231 /* {{{ parentNode	DomNode
232 readonly=yes
233 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1060184317
234 Since:
235 */
dom_node_parent_node_read(dom_object * obj,zval * retval)236 int dom_node_parent_node_read(dom_object *obj, zval *retval)
237 {
238 	xmlNode *nodep, *nodeparent;
239 
240 	nodep = dom_object_get_node(obj);
241 
242 	if (nodep == NULL) {
243 		php_dom_throw_error(INVALID_STATE_ERR, 0);
244 		return FAILURE;
245 	}
246 
247 	nodeparent = nodep->parent;
248 	if (!nodeparent) {
249 		ZVAL_NULL(retval);
250 		return SUCCESS;
251 	}
252 
253 	php_dom_create_object(nodeparent, retval, obj);
254 	return SUCCESS;
255 }
256 
257 /* }}} */
258 
259 /* {{{ childNodes	DomNodeList
260 readonly=yes
261 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1451460987
262 Since:
263 */
dom_node_child_nodes_read(dom_object * obj,zval * retval)264 int dom_node_child_nodes_read(dom_object *obj, zval *retval)
265 {
266 	xmlNode *nodep = dom_object_get_node(obj);
267 	dom_object *intern;
268 
269 	if (nodep == NULL) {
270 		php_dom_throw_error(INVALID_STATE_ERR, 0);
271 		return FAILURE;
272 	}
273 
274 	php_dom_create_iterator(retval, DOM_NODELIST);
275 	intern = Z_DOMOBJ_P(retval);
276 	dom_namednode_iter(obj, XML_ELEMENT_NODE, intern, NULL, NULL, NULL);
277 
278 	return SUCCESS;
279 }
280 /* }}} */
281 
282 /* {{{ firstChild DomNode
283 readonly=yes
284 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-169727388
285 Since:
286 */
dom_node_first_child_read(dom_object * obj,zval * retval)287 int dom_node_first_child_read(dom_object *obj, zval *retval)
288 {
289 	xmlNode *nodep, *first = NULL;
290 
291 	nodep = dom_object_get_node(obj);
292 
293 	if (nodep == NULL) {
294 		php_dom_throw_error(INVALID_STATE_ERR, 0);
295 		return FAILURE;
296 	}
297 
298 	if (dom_node_children_valid(nodep) == SUCCESS) {
299 		first = nodep->children;
300 	}
301 
302 	if (!first) {
303 		ZVAL_NULL(retval);
304 		return SUCCESS;
305 	}
306 
307 	php_dom_create_object(first, retval, obj);
308 	return SUCCESS;
309 }
310 
311 /* }}} */
312 
313 /* {{{ lastChild	DomNode
314 readonly=yes
315 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-61AD09FB
316 Since:
317 */
dom_node_last_child_read(dom_object * obj,zval * retval)318 int dom_node_last_child_read(dom_object *obj, zval *retval)
319 {
320 	xmlNode *nodep, *last = NULL;
321 
322 	nodep = dom_object_get_node(obj);
323 
324 	if (nodep == NULL) {
325 		php_dom_throw_error(INVALID_STATE_ERR, 0);
326 		return FAILURE;
327 	}
328 
329 	if (dom_node_children_valid(nodep) == SUCCESS) {
330 		last = nodep->last;
331 	}
332 
333 	if (!last) {
334 		ZVAL_NULL(retval);
335 		return SUCCESS;
336 	}
337 
338 	php_dom_create_object(last, retval, obj);
339 	return SUCCESS;
340 }
341 
342 /* }}} */
343 
344 /* {{{ previousSibling	DomNode
345 readonly=yes
346 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-640FB3C8
347 Since:
348 */
dom_node_previous_sibling_read(dom_object * obj,zval * retval)349 int dom_node_previous_sibling_read(dom_object *obj, zval *retval)
350 {
351 	xmlNode *nodep, *prevsib;
352 
353 	nodep = dom_object_get_node(obj);
354 
355 	if (nodep == NULL) {
356 		php_dom_throw_error(INVALID_STATE_ERR, 0);
357 		return FAILURE;
358 	}
359 
360 	prevsib = nodep->prev;
361 	if (!prevsib) {
362 		ZVAL_NULL(retval);
363 		return SUCCESS;
364 	}
365 
366 	php_dom_create_object(prevsib, retval, obj);
367 	return SUCCESS;
368 }
369 
370 /* }}} */
371 
372 /* {{{ nextSibling	DomNode
373 readonly=yes
374 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-6AC54C2F
375 Since:
376 */
dom_node_next_sibling_read(dom_object * obj,zval * retval)377 int dom_node_next_sibling_read(dom_object *obj, zval *retval)
378 {
379 	xmlNode *nodep, *nextsib;
380 
381 	nodep = dom_object_get_node(obj);
382 
383 	if (nodep == NULL) {
384 		php_dom_throw_error(INVALID_STATE_ERR, 0);
385 		return FAILURE;
386 	}
387 
388 	nextsib = nodep->next;
389 	if (!nextsib) {
390 		ZVAL_NULL(retval);
391 		return SUCCESS;
392 	}
393 
394 	php_dom_create_object(nextsib, retval, obj);
395 	return SUCCESS;
396 }
397 
398 /* }}} */
399 
400 /* {{{ previousElementSibling	DomNode
401 readonly=yes
402 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-640FB3C8
403 Since:
404 */
dom_node_previous_element_sibling_read(dom_object * obj,zval * retval)405 int dom_node_previous_element_sibling_read(dom_object *obj, zval *retval)
406 {
407 	xmlNode *nodep, *prevsib;
408 
409 	nodep = dom_object_get_node(obj);
410 
411 	if (nodep == NULL) {
412 		php_dom_throw_error(INVALID_STATE_ERR, 0);
413 		return FAILURE;
414 	}
415 
416 	prevsib = nodep->prev;
417 
418 	while (prevsib && prevsib->type != XML_ELEMENT_NODE) {
419 		prevsib = prevsib->prev;
420 	}
421 
422 	if (!prevsib) {
423 		ZVAL_NULL(retval);
424 		return SUCCESS;
425 	}
426 
427 	php_dom_create_object(prevsib, retval, obj);
428 	return SUCCESS;
429 }
430 
431 /* }}} */
432 
433 /* {{{ nextElementSibling	DomNode
434 readonly=yes
435 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-6AC54C2F
436 Since:
437 */
dom_node_next_element_sibling_read(dom_object * obj,zval * retval)438 int dom_node_next_element_sibling_read(dom_object *obj, zval *retval)
439 {
440 	xmlNode *nodep, *nextsib;
441 
442 	nodep = dom_object_get_node(obj);
443 
444 	if (nodep == NULL) {
445 		php_dom_throw_error(INVALID_STATE_ERR, 0);
446 		return FAILURE;
447 	}
448 
449 	nextsib = nodep->next;
450 
451 	while (nextsib != NULL && nextsib->type != XML_ELEMENT_NODE) {
452 		nextsib = nextsib->next;
453 	}
454 
455 	if (!nextsib) {
456 		ZVAL_NULL(retval);
457 		return SUCCESS;
458 	}
459 
460 	php_dom_create_object(nextsib, retval, obj);
461 	return SUCCESS;
462 }
463 
464 /* }}} */
465 
466 /* {{{ attributes	DomNamedNodeMap
467 readonly=yes
468 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-84CF096
469 Since:
470 */
dom_node_attributes_read(dom_object * obj,zval * retval)471 int dom_node_attributes_read(dom_object *obj, zval *retval)
472 {
473 	xmlNode *nodep = dom_object_get_node(obj);
474 	dom_object *intern;
475 
476 	if (nodep == NULL) {
477 		php_dom_throw_error(INVALID_STATE_ERR, 0);
478 		return FAILURE;
479 	}
480 
481 	if (nodep->type == XML_ELEMENT_NODE) {
482 		php_dom_create_iterator(retval, DOM_NAMEDNODEMAP);
483 		intern = Z_DOMOBJ_P(retval);
484 		dom_namednode_iter(obj, XML_ATTRIBUTE_NODE, intern, NULL, NULL, NULL);
485 	} else {
486 		ZVAL_NULL(retval);
487 	}
488 
489 	return SUCCESS;
490 }
491 
492 /* }}} */
493 
494 /* {{{ ownerDocument	DomDocument
495 readonly=yes
496 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-node-ownerDoc
497 Since:
498 */
dom_node_owner_document_read(dom_object * obj,zval * retval)499 int dom_node_owner_document_read(dom_object *obj, zval *retval)
500 {
501 	xmlNode *nodep = dom_object_get_node(obj);
502 	xmlDocPtr docp;
503 
504 	if (nodep == NULL) {
505 		php_dom_throw_error(INVALID_STATE_ERR, 0);
506 		return FAILURE;
507 	}
508 
509 	if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
510 		ZVAL_NULL(retval);
511 		return SUCCESS;
512 	}
513 
514 	docp = nodep->doc;
515 	if (!docp) {
516 		return FAILURE;
517 	}
518 
519 	php_dom_create_object((xmlNodePtr) docp, retval, obj);
520 	return SUCCESS;
521 }
522 
523 /* }}} */
524 
525 /* {{{ namespaceUri	string
526 readonly=yes
527 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-NodeNSname
528 Since: DOM Level 2
529 */
dom_node_namespace_uri_read(dom_object * obj,zval * retval)530 int dom_node_namespace_uri_read(dom_object *obj, zval *retval)
531 {
532 	xmlNode *nodep = dom_object_get_node(obj);
533 	char *str = NULL;
534 
535 	if (nodep == NULL) {
536 		php_dom_throw_error(INVALID_STATE_ERR, 0);
537 		return FAILURE;
538 	}
539 
540 	switch (nodep->type) {
541 		case XML_ELEMENT_NODE:
542 		case XML_ATTRIBUTE_NODE:
543 		case XML_NAMESPACE_DECL:
544 			if (nodep->ns != NULL) {
545 				str = (char *) nodep->ns->href;
546 			}
547 			break;
548 		default:
549 			str = NULL;
550 			break;
551 	}
552 
553 	if (str != NULL) {
554 		ZVAL_STRING(retval, str);
555 	} else {
556 		ZVAL_NULL(retval);
557 	}
558 
559 	return SUCCESS;
560 }
561 
562 /* }}} */
563 
564 /* {{{ prefix	string
565 readonly=no
566 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-NodeNSPrefix
567 Since: DOM Level 2
568 */
dom_node_prefix_read(dom_object * obj,zval * retval)569 int dom_node_prefix_read(dom_object *obj, zval *retval)
570 {
571 	xmlNode *nodep = dom_object_get_node(obj);
572 	xmlNsPtr ns;
573 	char *str = NULL;
574 
575 	if (nodep == NULL) {
576 		php_dom_throw_error(INVALID_STATE_ERR, 0);
577 		return FAILURE;
578 	}
579 
580 	switch (nodep->type) {
581 		case XML_ELEMENT_NODE:
582 		case XML_ATTRIBUTE_NODE:
583 		case XML_NAMESPACE_DECL:
584 			ns = nodep->ns;
585 			if (ns != NULL && ns->prefix) {
586 				str = (char *) ns->prefix;
587 			}
588 			break;
589 		default:
590 			str = NULL;
591 			break;
592 	}
593 
594 	if (str == NULL) {
595 		ZVAL_EMPTY_STRING(retval);
596 	} else {
597 		ZVAL_STRING(retval, str);
598 	}
599 	return SUCCESS;
600 
601 }
602 
dom_node_prefix_write(dom_object * obj,zval * newval)603 int dom_node_prefix_write(dom_object *obj, zval *newval)
604 {
605 	zend_string *str;
606 	xmlNode *nodep, *nsnode = NULL;
607 	xmlNsPtr ns = NULL, curns;
608 	char *strURI;
609 	char *prefix;
610 
611 	nodep = dom_object_get_node(obj);
612 
613 	if (nodep == NULL) {
614 		php_dom_throw_error(INVALID_STATE_ERR, 0);
615 		return FAILURE;
616 	}
617 
618 	switch (nodep->type) {
619 		case XML_ELEMENT_NODE:
620 			nsnode = nodep;
621 		case XML_ATTRIBUTE_NODE:
622 			if (nsnode == NULL) {
623 				nsnode = nodep->parent;
624 				if (nsnode == NULL) {
625 					nsnode = xmlDocGetRootElement(nodep->doc);
626 				}
627 			}
628 			str = zval_try_get_string(newval);
629 			if (UNEXPECTED(!str)) {
630 				return FAILURE;
631 			}
632 
633 			prefix = ZSTR_VAL(str);
634 			if (nsnode && nodep->ns != NULL && !xmlStrEqual(nodep->ns->prefix, (xmlChar *)prefix)) {
635 				strURI = (char *) nodep->ns->href;
636 				if (strURI == NULL ||
637 					(!strcmp(prefix, "xml") && strcmp(strURI, (char *) XML_XML_NAMESPACE)) ||
638 					(nodep->type == XML_ATTRIBUTE_NODE && !strcmp(prefix, "xmlns") &&
639 					 strcmp(strURI, (char *) DOM_XMLNS_NAMESPACE)) ||
640 					(nodep->type == XML_ATTRIBUTE_NODE && !strcmp((char *) nodep->name, "xmlns"))) {
641 					ns = NULL;
642 				} else {
643 					curns = nsnode->nsDef;
644 					while (curns != NULL) {
645 						if (xmlStrEqual((xmlChar *)prefix, curns->prefix) && xmlStrEqual(nodep->ns->href, curns->href)) {
646 							ns = curns;
647 							break;
648 						}
649 						curns = curns->next;
650 					}
651 					if (ns == NULL) {
652 						ns = xmlNewNs(nsnode, nodep->ns->href, (xmlChar *)prefix);
653 					}
654 				}
655 
656 				if (ns == NULL) {
657 					zend_string_release_ex(str, 0);
658 					php_dom_throw_error(NAMESPACE_ERR, dom_get_strict_error(obj->document));
659 					return FAILURE;
660 				}
661 
662 				xmlSetNs(nodep, ns);
663 			}
664 			zend_string_release_ex(str, 0);
665 			break;
666 		default:
667 			break;
668 	}
669 
670 	return SUCCESS;
671 }
672 
673 /* }}} */
674 
675 /* {{{ localName	string
676 readonly=yes
677 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-NodeNSLocalN
678 Since: DOM Level 2
679 */
dom_node_local_name_read(dom_object * obj,zval * retval)680 int dom_node_local_name_read(dom_object *obj, zval *retval)
681 {
682 	xmlNode *nodep = dom_object_get_node(obj);
683 
684 	if (nodep == NULL) {
685 		php_dom_throw_error(INVALID_STATE_ERR, 0);
686 		return FAILURE;
687 	}
688 
689 	if (nodep->type == XML_ELEMENT_NODE || nodep->type == XML_ATTRIBUTE_NODE || nodep->type == XML_NAMESPACE_DECL) {
690 		ZVAL_STRING(retval, (char *) (nodep->name));
691 	} else {
692 		ZVAL_NULL(retval);
693 	}
694 
695 	return SUCCESS;
696 }
697 
698 /* }}} */
699 
700 /* {{{ baseURI	string
701 readonly=yes
702 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#Node3-baseURI
703 Since: DOM Level 3
704 */
dom_node_base_uri_read(dom_object * obj,zval * retval)705 int dom_node_base_uri_read(dom_object *obj, zval *retval)
706 {
707 	xmlNode *nodep = dom_object_get_node(obj);
708 	xmlChar *baseuri;
709 
710 	if (nodep == NULL) {
711 		php_dom_throw_error(INVALID_STATE_ERR, 0);
712 		return FAILURE;
713 	}
714 
715 	baseuri = xmlNodeGetBase(nodep->doc, nodep);
716 	if (baseuri) {
717 		ZVAL_STRING(retval, (char *) (baseuri));
718 		xmlFree(baseuri);
719 	} else {
720 		ZVAL_NULL(retval);
721 	}
722 
723 	return SUCCESS;
724 }
725 
726 /* }}} */
727 
728 /* {{{ textContent	string
729 readonly=no
730 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#Node3-textContent
731 Since: DOM Level 3
732 */
dom_node_text_content_read(dom_object * obj,zval * retval)733 int dom_node_text_content_read(dom_object *obj, zval *retval)
734 {
735 	xmlNode *nodep = dom_object_get_node(obj);
736 	char *str = NULL;
737 
738 	if (nodep == NULL) {
739 		php_dom_throw_error(INVALID_STATE_ERR, 0);
740 		return FAILURE;
741 	}
742 
743 	str = (char *) xmlNodeGetContent(nodep);
744 
745 	if (str != NULL) {
746 		ZVAL_STRING(retval, str);
747 		xmlFree(str);
748 	} else {
749 		ZVAL_EMPTY_STRING(retval);
750 	}
751 
752 	return SUCCESS;
753 }
754 
dom_node_text_content_write(dom_object * obj,zval * newval)755 int dom_node_text_content_write(dom_object *obj, zval *newval)
756 {
757 	xmlNode *nodep = dom_object_get_node(obj);
758 	zend_string *str;
759 
760 	if (nodep == NULL) {
761 		php_dom_throw_error(INVALID_STATE_ERR, 0);
762 		return FAILURE;
763 	}
764 
765 	str = zval_try_get_string(newval);
766 	if (UNEXPECTED(!str)) {
767 		return FAILURE;
768 	}
769 
770 	if (nodep->type == XML_ELEMENT_NODE || nodep->type == XML_ATTRIBUTE_NODE) {
771 		if (nodep->children) {
772 			node_list_unlink(nodep->children);
773 			php_libxml_node_free_list((xmlNodePtr) nodep->children);
774 			nodep->children = NULL;
775 		}
776 	}
777 
778 	/* we have to use xmlNodeAddContent() to get the same behavior as with xmlNewText() */
779 	xmlNodeSetContent(nodep, (xmlChar *) "");
780 	xmlNodeAddContent(nodep, (xmlChar *) ZSTR_VAL(str));
781 	zend_string_release_ex(str, 0);
782 
783 	return SUCCESS;
784 }
785 
786 /* }}} */
787 
_php_dom_insert_fragment(xmlNodePtr nodep,xmlNodePtr prevsib,xmlNodePtr nextsib,xmlNodePtr fragment,dom_object * intern,dom_object * childobj)788 static xmlNodePtr _php_dom_insert_fragment(xmlNodePtr nodep, xmlNodePtr prevsib, xmlNodePtr nextsib, xmlNodePtr fragment, dom_object *intern, dom_object *childobj) /* {{{ */
789 {
790 	xmlNodePtr newchild, node;
791 
792 	newchild = fragment->children;
793 
794 	if (newchild) {
795 		if (prevsib == NULL) {
796 			nodep->children = newchild;
797 		} else {
798 			prevsib->next = newchild;
799 		}
800 		newchild->prev = prevsib;
801 		if (nextsib == NULL) {
802 			nodep->last = fragment->last;
803 		} else {
804 			fragment->last->next = nextsib;
805 			nextsib->prev = fragment->last;
806 		}
807 
808 		node = newchild;
809 		while (node != NULL) {
810 			node->parent = nodep;
811 			if (node->doc != nodep->doc) {
812 				xmlSetTreeDoc(node, nodep->doc);
813 				if (node->_private != NULL) {
814 					childobj = node->_private;
815 					childobj->document = intern->document;
816 					php_libxml_increment_doc_ref((php_libxml_node_object *)childobj, NULL);
817 				}
818 			}
819 			if (node == fragment->last) {
820 				break;
821 			}
822 			node = node->next;
823 		}
824 
825 		fragment->children = NULL;
826 		fragment->last = NULL;
827 	}
828 
829 	return newchild;
830 }
831 /* }}} */
832 
833 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-952280727
834 Since:
835 */
PHP_METHOD(DOMNode,insertBefore)836 PHP_METHOD(DOMNode, insertBefore)
837 {
838 	zval *id, *node, *ref = NULL;
839 	xmlNodePtr child, new_child, parentp, refp;
840 	dom_object *intern, *childobj, *refpobj;
841 	int ret, stricterror;
842 
843 	id = ZEND_THIS;
844 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|O!", &node, dom_node_class_entry, &ref, dom_node_class_entry) == FAILURE) {
845 		RETURN_THROWS();
846 	}
847 
848 	DOM_GET_OBJ(parentp, id, xmlNodePtr, intern);
849 
850 	if (dom_node_children_valid(parentp) == FAILURE) {
851 		RETURN_FALSE;
852 	}
853 
854 	DOM_GET_OBJ(child, node, xmlNodePtr, childobj);
855 
856 	new_child = NULL;
857 
858 	stricterror = dom_get_strict_error(intern->document);
859 
860 	if (dom_node_is_read_only(parentp) == SUCCESS ||
861 		(child->parent != NULL && dom_node_is_read_only(child->parent) == SUCCESS)) {
862 		php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, stricterror);
863 		RETURN_FALSE;
864 	}
865 
866 	if (dom_hierarchy(parentp, child) == FAILURE) {
867 		php_dom_throw_error(HIERARCHY_REQUEST_ERR, stricterror);
868 		RETURN_FALSE;
869 	}
870 
871 	if (child->doc != parentp->doc && child->doc != NULL) {
872 		php_dom_throw_error(WRONG_DOCUMENT_ERR, stricterror);
873 		RETURN_FALSE;
874 	}
875 
876 	if (child->type == XML_DOCUMENT_FRAG_NODE && child->children == NULL) {
877 		/* TODO Drop Warning? */
878 		php_error_docref(NULL, E_WARNING, "Document Fragment is empty");
879 		RETURN_FALSE;
880 	}
881 
882 	if (child->doc == NULL && parentp->doc != NULL) {
883 		childobj->document = intern->document;
884 		php_libxml_increment_doc_ref((php_libxml_node_object *)childobj, NULL);
885 	}
886 
887 	if (ref != NULL) {
888 		DOM_GET_OBJ(refp, ref, xmlNodePtr, refpobj);
889 		if (refp->parent != parentp) {
890 			php_dom_throw_error(NOT_FOUND_ERR, stricterror);
891 			RETURN_FALSE;
892 		}
893 
894 		if (child->parent != NULL) {
895 			xmlUnlinkNode(child);
896 		}
897 
898 		if (child->type == XML_TEXT_NODE && (refp->type == XML_TEXT_NODE ||
899 			(refp->prev != NULL && refp->prev->type == XML_TEXT_NODE))) {
900 			if (child->doc == NULL) {
901 				xmlSetTreeDoc(child, parentp->doc);
902 			}
903 			new_child = child;
904 			new_child->parent = refp->parent;
905 			new_child->next = refp;
906 			new_child->prev = refp->prev;
907 			refp->prev = new_child;
908 			if (new_child->prev != NULL) {
909 				new_child->prev->next = new_child;
910 			}
911 			if (new_child->parent != NULL) {
912 				if (new_child->parent->children == refp) {
913 					new_child->parent->children = new_child;
914 				}
915 			}
916 
917 		} else if (child->type == XML_ATTRIBUTE_NODE) {
918 			xmlAttrPtr lastattr;
919 
920 			if (child->ns == NULL)
921 				lastattr = xmlHasProp(refp->parent, child->name);
922 			else
923 				lastattr = xmlHasNsProp(refp->parent, child->name, child->ns->href);
924 			if (lastattr != NULL && lastattr->type != XML_ATTRIBUTE_DECL) {
925 				if (lastattr != (xmlAttrPtr) child) {
926 					xmlUnlinkNode((xmlNodePtr) lastattr);
927 					php_libxml_node_free_resource((xmlNodePtr) lastattr);
928 				} else {
929 					DOM_RET_OBJ(child, &ret, intern);
930 					return;
931 				}
932 			}
933 		} else if (child->type == XML_DOCUMENT_FRAG_NODE) {
934 			new_child = _php_dom_insert_fragment(parentp, refp->prev, refp, child, intern, childobj);
935 		}
936 
937 		if (new_child == NULL) {
938 			new_child = xmlAddPrevSibling(refp, child);
939 		}
940 	} else {
941 		if (child->parent != NULL){
942 			xmlUnlinkNode(child);
943 		}
944 		if (child->type == XML_TEXT_NODE && parentp->last != NULL && parentp->last->type == XML_TEXT_NODE) {
945 			child->parent = parentp;
946 			if (child->doc == NULL) {
947 				xmlSetTreeDoc(child, parentp->doc);
948 			}
949 			new_child = child;
950 			if (parentp->children == NULL) {
951 				parentp->children = child;
952 				parentp->last = child;
953 			} else {
954 				child = parentp->last;
955 				child->next = new_child;
956 				new_child->prev = child;
957 				parentp->last = new_child;
958 			}
959 		} else 	if (child->type == XML_ATTRIBUTE_NODE) {
960 			xmlAttrPtr lastattr;
961 
962 			if (child->ns == NULL)
963 				lastattr = xmlHasProp(parentp, child->name);
964 			else
965 				lastattr = xmlHasNsProp(parentp, child->name, child->ns->href);
966 			if (lastattr != NULL && lastattr->type != XML_ATTRIBUTE_DECL) {
967 				if (lastattr != (xmlAttrPtr) child) {
968 					xmlUnlinkNode((xmlNodePtr) lastattr);
969 					php_libxml_node_free_resource((xmlNodePtr) lastattr);
970 				} else {
971 					DOM_RET_OBJ(child, &ret, intern);
972 					return;
973 				}
974 			}
975 		} else if (child->type == XML_DOCUMENT_FRAG_NODE) {
976 			new_child = _php_dom_insert_fragment(parentp, parentp->last, NULL, child, intern, childobj);
977 		}
978 		if (new_child == NULL) {
979 			new_child = xmlAddChild(parentp, child);
980 		}
981 	}
982 
983 	if (NULL == new_child) {
984 		zend_throw_error(NULL, "Cannot add newnode as the previous sibling of refnode");
985 		RETURN_THROWS();
986 	}
987 
988 	dom_reconcile_ns(parentp->doc, new_child);
989 
990 	DOM_RET_OBJ(new_child, &ret, intern);
991 
992 }
993 /* }}} end dom_node_insert_before */
994 
995 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-785887307
996 Since:
997 */
PHP_METHOD(DOMNode,replaceChild)998 PHP_METHOD(DOMNode, replaceChild)
999 {
1000 	zval *id, *newnode, *oldnode;
1001 	xmlNodePtr children, newchild, oldchild, nodep;
1002 	dom_object *intern, *newchildobj, *oldchildobj;
1003 	int foundoldchild = 0, stricterror;
1004 
1005 	int ret;
1006 
1007 	id = ZEND_THIS;
1008 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "OO", &newnode, dom_node_class_entry, &oldnode, dom_node_class_entry) == FAILURE) {
1009 		RETURN_THROWS();
1010 	}
1011 
1012 	DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
1013 
1014 	if (dom_node_children_valid(nodep) == FAILURE) {
1015 		RETURN_FALSE;
1016 	}
1017 
1018 	DOM_GET_OBJ(newchild, newnode, xmlNodePtr, newchildobj);
1019 	DOM_GET_OBJ(oldchild, oldnode, xmlNodePtr, oldchildobj);
1020 
1021 	children = nodep->children;
1022 	if (!children) {
1023 		RETURN_FALSE;
1024 	}
1025 
1026 	stricterror = dom_get_strict_error(intern->document);
1027 
1028 	if (dom_node_is_read_only(nodep) == SUCCESS ||
1029 		(newchild->parent != NULL && dom_node_is_read_only(newchild->parent) == SUCCESS)) {
1030 		php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, stricterror);
1031 		RETURN_FALSE;
1032 	}
1033 
1034 	if (newchild->doc != nodep->doc && newchild->doc != NULL) {
1035 		php_dom_throw_error(WRONG_DOCUMENT_ERR, stricterror);
1036 		RETURN_FALSE;
1037 	}
1038 
1039 	if (dom_hierarchy(nodep, newchild) == FAILURE) {
1040 		php_dom_throw_error(HIERARCHY_REQUEST_ERR, stricterror);
1041 		RETURN_FALSE;
1042 	}
1043 
1044 	/* check for the old child and whether the new child is already a child */
1045 	while (children) {
1046 		if (children == oldchild) {
1047 			foundoldchild = 1;
1048 			break;
1049 		}
1050 		children = children->next;
1051 	}
1052 
1053 	if (foundoldchild) {
1054 		if (newchild->type == XML_DOCUMENT_FRAG_NODE) {
1055 			xmlNodePtr prevsib, nextsib;
1056 			prevsib = oldchild->prev;
1057 			nextsib = oldchild->next;
1058 
1059 			xmlUnlinkNode(oldchild);
1060 
1061 			newchild = _php_dom_insert_fragment(nodep, prevsib, nextsib, newchild, intern, newchildobj);
1062 			if (newchild) {
1063 				dom_reconcile_ns(nodep->doc, newchild);
1064 			}
1065 		} else if (oldchild != newchild) {
1066 			if (newchild->doc == NULL && nodep->doc != NULL) {
1067 				xmlSetTreeDoc(newchild, nodep->doc);
1068 				newchildobj->document = intern->document;
1069 				php_libxml_increment_doc_ref((php_libxml_node_object *)newchildobj, NULL);
1070 			}
1071 			xmlReplaceNode(oldchild, newchild);
1072 			dom_reconcile_ns(nodep->doc, newchild);
1073 		}
1074 		DOM_RET_OBJ(oldchild, &ret, intern);
1075 		return;
1076 	} else {
1077 		php_dom_throw_error(NOT_FOUND_ERR, stricterror);
1078 		RETURN_FALSE;
1079 	}
1080 }
1081 /* }}} end dom_node_replace_child */
1082 
1083 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1734834066
1084 Since:
1085 */
PHP_METHOD(DOMNode,removeChild)1086 PHP_METHOD(DOMNode, removeChild)
1087 {
1088 	zval *id, *node;
1089 	xmlNodePtr children, child, nodep;
1090 	dom_object *intern, *childobj;
1091 	int ret, stricterror;
1092 
1093 	id = ZEND_THIS;
1094 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &node, dom_node_class_entry) == FAILURE) {
1095 		RETURN_THROWS();
1096 	}
1097 
1098 	DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
1099 
1100 	if (dom_node_children_valid(nodep) == FAILURE) {
1101 		RETURN_FALSE;
1102 	}
1103 
1104 	DOM_GET_OBJ(child, node, xmlNodePtr, childobj);
1105 
1106 	stricterror = dom_get_strict_error(intern->document);
1107 
1108 	if (dom_node_is_read_only(nodep) == SUCCESS ||
1109 		(child->parent != NULL && dom_node_is_read_only(child->parent) == SUCCESS)) {
1110 		php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, stricterror);
1111 		RETURN_FALSE;
1112 	}
1113 
1114 	children = nodep->children;
1115 	if (!children) {
1116 		php_dom_throw_error(NOT_FOUND_ERR, stricterror);
1117 		RETURN_FALSE;
1118 	}
1119 
1120 	while (children) {
1121 		if (children == child) {
1122 			xmlUnlinkNode(child);
1123 			DOM_RET_OBJ(child, &ret, intern);
1124 			return;
1125 		}
1126 		children = children->next;
1127 	}
1128 
1129 	php_dom_throw_error(NOT_FOUND_ERR, stricterror);
1130 	RETURN_FALSE;
1131 }
1132 /* }}} end dom_node_remove_child */
1133 
1134 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-184E7107
1135 Since:
1136 */
PHP_METHOD(DOMNode,appendChild)1137 PHP_METHOD(DOMNode, appendChild)
1138 {
1139 	zval *id, *node;
1140 	xmlNodePtr child, nodep, new_child = NULL;
1141 	dom_object *intern, *childobj;
1142 	int ret, stricterror;
1143 
1144 	id = ZEND_THIS;
1145 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &node, dom_node_class_entry) == FAILURE) {
1146 		RETURN_THROWS();
1147 	}
1148 
1149 	DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
1150 
1151 	if (dom_node_children_valid(nodep) == FAILURE) {
1152 		RETURN_FALSE;
1153 	}
1154 
1155 	DOM_GET_OBJ(child, node, xmlNodePtr, childobj);
1156 
1157 	stricterror = dom_get_strict_error(intern->document);
1158 
1159 	if (dom_node_is_read_only(nodep) == SUCCESS ||
1160 		(child->parent != NULL && dom_node_is_read_only(child->parent) == SUCCESS)) {
1161 		php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, stricterror);
1162 		RETURN_FALSE;
1163 	}
1164 
1165 	if (dom_hierarchy(nodep, child) == FAILURE) {
1166 		php_dom_throw_error(HIERARCHY_REQUEST_ERR, stricterror);
1167 		RETURN_FALSE;
1168 	}
1169 
1170 	if (!(child->doc == NULL || child->doc == nodep->doc)) {
1171 		php_dom_throw_error(WRONG_DOCUMENT_ERR, stricterror);
1172 		RETURN_FALSE;
1173 	}
1174 
1175 	if (child->type == XML_DOCUMENT_FRAG_NODE && child->children == NULL) {
1176 		/* TODO Drop Warning? */
1177 		php_error_docref(NULL, E_WARNING, "Document Fragment is empty");
1178 		RETURN_FALSE;
1179 	}
1180 
1181 	if (child->doc == NULL && nodep->doc != NULL) {
1182 		childobj->document = intern->document;
1183 		php_libxml_increment_doc_ref((php_libxml_node_object *)childobj, NULL);
1184 	}
1185 
1186 	if (child->parent != NULL){
1187 		xmlUnlinkNode(child);
1188 	}
1189 
1190 	if (child->type == XML_TEXT_NODE && nodep->last != NULL && nodep->last->type == XML_TEXT_NODE) {
1191 		child->parent = nodep;
1192 		if (child->doc == NULL) {
1193 			xmlSetTreeDoc(child, nodep->doc);
1194 		}
1195 		new_child = child;
1196 		if (nodep->children == NULL) {
1197 			nodep->children = child;
1198 			nodep->last = child;
1199 		} else {
1200 			child = nodep->last;
1201 			child->next = new_child;
1202 			new_child->prev = child;
1203 			nodep->last = new_child;
1204 		}
1205 	} else 	if (child->type == XML_ATTRIBUTE_NODE) {
1206 		xmlAttrPtr lastattr;
1207 
1208 		if (child->ns == NULL)
1209 			lastattr = xmlHasProp(nodep, child->name);
1210 		else
1211 			lastattr = xmlHasNsProp(nodep, child->name, child->ns->href);
1212 		if (lastattr != NULL && lastattr->type != XML_ATTRIBUTE_DECL) {
1213 			if (lastattr != (xmlAttrPtr) child) {
1214 				xmlUnlinkNode((xmlNodePtr) lastattr);
1215 				php_libxml_node_free_resource((xmlNodePtr) lastattr);
1216 			}
1217 		}
1218 	} else if (child->type == XML_DOCUMENT_FRAG_NODE) {
1219 		new_child = _php_dom_insert_fragment(nodep, nodep->last, NULL, child, intern, childobj);
1220 	}
1221 
1222 	if (new_child == NULL) {
1223 		new_child = xmlAddChild(nodep, child);
1224 		if (new_child == NULL) {
1225 			// TODO Convert to Error?
1226 			php_error_docref(NULL, E_WARNING, "Couldn't append node");
1227 			RETURN_FALSE;
1228 		}
1229 	}
1230 
1231 	dom_reconcile_ns(nodep->doc, new_child);
1232 
1233 	DOM_RET_OBJ(new_child, &ret, intern);
1234 }
1235 /* }}} end dom_node_append_child */
1236 
1237 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-810594187
1238 Since:
1239 */
PHP_METHOD(DOMNode,hasChildNodes)1240 PHP_METHOD(DOMNode, hasChildNodes)
1241 {
1242 	zval *id;
1243 	xmlNode *nodep;
1244 	dom_object *intern;
1245 
1246 	id = ZEND_THIS;
1247 	if (zend_parse_parameters_none() == FAILURE) {
1248 		RETURN_THROWS();
1249 	}
1250 
1251 	DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
1252 
1253 	if (dom_node_children_valid(nodep) == FAILURE) {
1254 		RETURN_FALSE;
1255 	}
1256 
1257 	if (nodep->children) {
1258 		RETURN_TRUE;
1259 	} else {
1260 		RETURN_FALSE;
1261 	}
1262 }
1263 /* }}} end dom_node_has_child_nodes */
1264 
1265 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-3A0ED0A4
1266 Since:
1267 */
PHP_METHOD(DOMNode,cloneNode)1268 PHP_METHOD(DOMNode, cloneNode)
1269 {
1270 	zval *id;
1271 	xmlNode *n, *node;
1272 	int ret;
1273 	dom_object *intern;
1274 	zend_bool recursive = 0;
1275 
1276 	id = ZEND_THIS;
1277 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &recursive) == FAILURE) {
1278 		RETURN_THROWS();
1279 	}
1280 
1281 	DOM_GET_OBJ(n, id, xmlNodePtr, intern);
1282 
1283 	node = xmlDocCopyNode(n, n->doc, recursive);
1284 
1285 	if (!node) {
1286 		RETURN_FALSE;
1287 	}
1288 
1289 	/* When deep is false Element nodes still require the attributes
1290 	Following taken from libxml as xmlDocCopyNode doesn't do this */
1291 	if (n->type == XML_ELEMENT_NODE && recursive == 0) {
1292 		if (n->nsDef != NULL) {
1293 			node->nsDef = xmlCopyNamespaceList(n->nsDef);
1294 		}
1295 		if (n->ns != NULL) {
1296 			xmlNsPtr ns;
1297 			ns = xmlSearchNs(n->doc, node, n->ns->prefix);
1298 			if (ns == NULL) {
1299 				ns = xmlSearchNs(n->doc, n, n->ns->prefix);
1300 				if (ns != NULL) {
1301 					xmlNodePtr root = node;
1302 
1303 					while (root->parent != NULL) {
1304 						root = root->parent;
1305 					}
1306 					node->ns = xmlNewNs(root, ns->href, ns->prefix);
1307 				}
1308 			} else {
1309 				node->ns = ns;
1310 			}
1311 		}
1312 		if (n->properties != NULL) {
1313 			node->properties = xmlCopyPropList(node, n->properties);
1314 		}
1315 	}
1316 
1317 	/* If document cloned we want a new document proxy */
1318 	if (node->doc != n->doc) {
1319 		intern = NULL;
1320 	}
1321 
1322 	DOM_RET_OBJ(node, &ret, intern);
1323 }
1324 /* }}} end dom_node_clone_node */
1325 
1326 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-normalize
1327 Since:
1328 */
PHP_METHOD(DOMNode,normalize)1329 PHP_METHOD(DOMNode, normalize)
1330 {
1331 	zval *id;
1332 	xmlNode *nodep;
1333 	dom_object *intern;
1334 
1335 	id = ZEND_THIS;
1336 	if (zend_parse_parameters_none() == FAILURE) {
1337 		RETURN_THROWS();
1338 	}
1339 
1340 	DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
1341 
1342 	dom_normalize(nodep);
1343 
1344 }
1345 /* }}} end dom_node_normalize */
1346 
1347 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-Level-2-Core-Node-supports
1348 Since: DOM Level 2
1349 */
PHP_METHOD(DOMNode,isSupported)1350 PHP_METHOD(DOMNode, isSupported)
1351 {
1352 	size_t feature_len, version_len;
1353 	char *feature, *version;
1354 
1355 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &feature, &feature_len, &version, &version_len) == FAILURE) {
1356 		RETURN_THROWS();
1357 	}
1358 
1359 	if (dom_has_feature(feature, version)) {
1360 		RETURN_TRUE;
1361 	} else {
1362 		RETURN_FALSE;
1363 	}
1364 }
1365 /* }}} end dom_node_is_supported */
1366 
1367 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-NodeHasAttrs
1368 Since: DOM Level 2
1369 */
PHP_METHOD(DOMNode,hasAttributes)1370 PHP_METHOD(DOMNode, hasAttributes)
1371 {
1372 	zval *id;
1373 	xmlNode *nodep;
1374 	dom_object *intern;
1375 
1376 	id = ZEND_THIS;
1377 	if (zend_parse_parameters_none() == FAILURE) {
1378 		RETURN_THROWS();
1379 	}
1380 
1381 	DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
1382 
1383 	if (nodep->type != XML_ELEMENT_NODE)
1384 		RETURN_FALSE;
1385 
1386 	if (nodep->properties) {
1387 		RETURN_TRUE;
1388 	} else {
1389 		RETURN_FALSE;
1390 	}
1391 }
1392 /* }}} end dom_node_has_attributes */
1393 
1394 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#Node3-isSameNode
1395 Since: DOM Level 3
1396 */
PHP_METHOD(DOMNode,isSameNode)1397 PHP_METHOD(DOMNode, isSameNode)
1398 {
1399 	zval *id, *node;
1400 	xmlNodePtr nodeotherp, nodep;
1401 	dom_object *intern, *nodeotherobj;
1402 
1403 	id = ZEND_THIS;
1404 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &node, dom_node_class_entry) == FAILURE) {
1405 		RETURN_THROWS();
1406 	}
1407 
1408 	DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
1409 
1410 	DOM_GET_OBJ(nodeotherp, node, xmlNodePtr, nodeotherobj);
1411 
1412 	if (nodep == nodeotherp) {
1413 		RETURN_TRUE;
1414 	} else {
1415 		RETURN_FALSE;
1416 	}
1417 }
1418 /* }}} end dom_node_is_same_node */
1419 
1420 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#Node3-lookupNamespacePrefix
1421 Since: DOM Level 3
1422 */
PHP_METHOD(DOMNode,lookupPrefix)1423 PHP_METHOD(DOMNode, lookupPrefix)
1424 {
1425 	zval *id;
1426 	xmlNodePtr nodep, lookupp = NULL;
1427 	dom_object *intern;
1428 	xmlNsPtr nsptr;
1429 	size_t uri_len = 0;
1430 	char *uri;
1431 
1432 	id = ZEND_THIS;
1433 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &uri, &uri_len) == FAILURE) {
1434 		RETURN_THROWS();
1435 	}
1436 
1437 	DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
1438 
1439 	if (uri_len > 0) {
1440 		switch (nodep->type) {
1441 			case XML_ELEMENT_NODE:
1442 				lookupp = nodep;
1443 				break;
1444 			case XML_DOCUMENT_NODE:
1445 			case XML_HTML_DOCUMENT_NODE:
1446 				lookupp = xmlDocGetRootElement((xmlDocPtr) nodep);
1447 				break;
1448 			case XML_ENTITY_NODE :
1449 			case XML_NOTATION_NODE:
1450 			case XML_DOCUMENT_FRAG_NODE:
1451 			case XML_DOCUMENT_TYPE_NODE:
1452 			case XML_DTD_NODE:
1453 				RETURN_NULL();
1454 				break;
1455 			default:
1456 				lookupp =  nodep->parent;
1457 		}
1458 
1459 		if (lookupp != NULL) {
1460 			nsptr = xmlSearchNsByHref(lookupp->doc, lookupp, (xmlChar *) uri);
1461 			if (nsptr && nsptr->prefix != NULL) {
1462 				RETURN_STRING((char *) nsptr->prefix);
1463 			}
1464 		}
1465 	}
1466 
1467 	RETURN_NULL();
1468 }
1469 /* }}} end dom_node_lookup_prefix */
1470 
1471 /* {{{ URL: http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-isDefaultNamespace
1472 Since: DOM Level 3
1473 */
PHP_METHOD(DOMNode,isDefaultNamespace)1474 PHP_METHOD(DOMNode, isDefaultNamespace)
1475 {
1476 	zval *id;
1477 	xmlNodePtr nodep;
1478 	dom_object *intern;
1479 	xmlNsPtr nsptr;
1480 	size_t uri_len = 0;
1481 	char *uri;
1482 
1483 	id = ZEND_THIS;
1484 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &uri, &uri_len) == FAILURE) {
1485 		RETURN_THROWS();
1486 	}
1487 
1488 	DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
1489 	if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
1490 		nodep = xmlDocGetRootElement((xmlDocPtr) nodep);
1491 	}
1492 
1493 	if (nodep && uri_len > 0) {
1494 		nsptr = xmlSearchNs(nodep->doc, nodep, NULL);
1495 		if (nsptr && xmlStrEqual(nsptr->href, (xmlChar *) uri)) {
1496 			RETURN_TRUE;
1497 		}
1498 	}
1499 
1500 	RETURN_FALSE;
1501 }
1502 /* }}} end dom_node_is_default_namespace */
1503 
1504 /* {{{ URL: http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-lookupNamespaceURI
1505 Since: DOM Level 3
1506 */
PHP_METHOD(DOMNode,lookupNamespaceURI)1507 PHP_METHOD(DOMNode, lookupNamespaceURI)
1508 {
1509 	zval *id;
1510 	xmlNodePtr nodep;
1511 	dom_object *intern;
1512 	xmlNsPtr nsptr;
1513 	size_t prefix_len;
1514 	char *prefix;
1515 
1516 	id = ZEND_THIS;
1517 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s!", &prefix, &prefix_len) == FAILURE) {
1518 		RETURN_THROWS();
1519 	}
1520 
1521 	DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
1522 	if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
1523 		nodep = xmlDocGetRootElement((xmlDocPtr) nodep);
1524 		if (nodep == NULL) {
1525 			RETURN_NULL();
1526 		}
1527 	}
1528 
1529 	nsptr = xmlSearchNs(nodep->doc, nodep, (xmlChar *) prefix);
1530 	if (nsptr && nsptr->href != NULL) {
1531 		RETURN_STRING((char *) nsptr->href);
1532 	}
1533 
1534 	RETURN_NULL();
1535 }
1536 /* }}} end dom_node_lookup_namespace_uri */
1537 
dom_canonicalization(INTERNAL_FUNCTION_PARAMETERS,int mode)1538 static void dom_canonicalization(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ */
1539 {
1540 	zval *id;
1541 	zval *xpath_array=NULL, *ns_prefixes=NULL;
1542 	xmlNodePtr nodep;
1543 	xmlDocPtr docp;
1544 	xmlNodeSetPtr nodeset = NULL;
1545 	dom_object *intern;
1546 	zend_bool exclusive=0, with_comments=0;
1547 	xmlChar **inclusive_ns_prefixes = NULL;
1548 	char *file = NULL;
1549 	int ret = -1;
1550 	size_t file_len = 0;
1551 	xmlOutputBufferPtr buf;
1552 	xmlXPathContextPtr ctxp=NULL;
1553 	xmlXPathObjectPtr xpathobjp=NULL;
1554 
1555 	id = ZEND_THIS;
1556 	if (mode == 0) {
1557 		if (zend_parse_parameters(ZEND_NUM_ARGS(),
1558 			"|bba!a!", &exclusive, &with_comments,
1559 			&xpath_array, &ns_prefixes) == FAILURE) {
1560 			RETURN_THROWS();
1561 		}
1562 	} else {
1563 		if (zend_parse_parameters(ZEND_NUM_ARGS(),
1564 			"s|bba!a!", &file, &file_len, &exclusive,
1565 			&with_comments, &xpath_array, &ns_prefixes) == FAILURE) {
1566 			RETURN_THROWS();
1567 		}
1568 	}
1569 
1570 	DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
1571 
1572 	docp = nodep->doc;
1573 
1574 	if (! docp) {
1575 		zend_throw_error(NULL, "Node must be associated with a document");
1576 		RETURN_THROWS();
1577 	}
1578 
1579 	if (xpath_array == NULL) {
1580 		if (nodep->type != XML_DOCUMENT_NODE) {
1581 			ctxp = xmlXPathNewContext(docp);
1582 			ctxp->node = nodep;
1583 			xpathobjp = xmlXPathEvalExpression((xmlChar *) "(.//. | .//@* | .//namespace::*)", ctxp);
1584 			ctxp->node = NULL;
1585 			if (xpathobjp && xpathobjp->type == XPATH_NODESET) {
1586 				nodeset = xpathobjp->nodesetval;
1587 			} else {
1588 				if (xpathobjp) {
1589 					xmlXPathFreeObject(xpathobjp);
1590 				}
1591 				xmlXPathFreeContext(ctxp);
1592 				zend_throw_error(NULL, "XPath query did not return a nodeset");
1593 				RETURN_THROWS();
1594 			}
1595 		}
1596 	} else {
1597 		/*xpath query from xpath_array */
1598 		HashTable *ht = Z_ARRVAL_P(xpath_array);
1599 		zval *tmp;
1600 		char *xquery;
1601 
1602 		tmp = zend_hash_str_find(ht, "query", sizeof("query")-1);
1603 		if (!tmp) {
1604 			/* if mode == 0 then $xpath arg is 3, if mode == 1 then $xpath is 4 */
1605 			zend_argument_value_error(3 + mode, "must have a \"query\" key");
1606 			RETURN_THROWS();
1607 		}
1608 		if (Z_TYPE_P(tmp) != IS_STRING) {
1609 			/* if mode == 0 then $xpath arg is 3, if mode == 1 then $xpath is 4 */
1610 			zend_argument_type_error(3 + mode, "\"query\" option must be a string, %s given", zend_zval_type_name(tmp));
1611 			RETURN_THROWS();
1612 		}
1613 		xquery = Z_STRVAL_P(tmp);
1614 
1615 		ctxp = xmlXPathNewContext(docp);
1616 		ctxp->node = nodep;
1617 
1618 		tmp = zend_hash_str_find(ht, "namespaces", sizeof("namespaces")-1);
1619 		if (tmp && Z_TYPE_P(tmp) == IS_ARRAY) {
1620 			zval *tmpns;
1621 			zend_string *prefix;
1622 
1623 			ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(tmp), prefix, tmpns) {
1624 				if (Z_TYPE_P(tmpns) == IS_STRING) {
1625 					if (prefix) {
1626 						xmlXPathRegisterNs(ctxp, (xmlChar *) ZSTR_VAL(prefix), (xmlChar *) Z_STRVAL_P(tmpns));
1627 					}
1628 				}
1629 			} ZEND_HASH_FOREACH_END();
1630 		}
1631 
1632 		xpathobjp = xmlXPathEvalExpression((xmlChar *) xquery, ctxp);
1633 		ctxp->node = NULL;
1634 		if (xpathobjp && xpathobjp->type == XPATH_NODESET) {
1635 			nodeset = xpathobjp->nodesetval;
1636 		} else {
1637 			if (xpathobjp) {
1638 				xmlXPathFreeObject(xpathobjp);
1639 			}
1640 			xmlXPathFreeContext(ctxp);
1641 			zend_throw_error(NULL, "XPath query did not return a nodeset");
1642 			RETURN_THROWS();
1643 		}
1644 	}
1645 
1646 	if (ns_prefixes != NULL) {
1647 		if (exclusive) {
1648 			zval *tmpns;
1649 			int nscount = 0;
1650 
1651 			inclusive_ns_prefixes = safe_emalloc(zend_hash_num_elements(Z_ARRVAL_P(ns_prefixes)) + 1,
1652 				sizeof(xmlChar *), 0);
1653 			ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(ns_prefixes), tmpns) {
1654 				if (Z_TYPE_P(tmpns) == IS_STRING) {
1655 					inclusive_ns_prefixes[nscount++] = (xmlChar *) Z_STRVAL_P(tmpns);
1656 				}
1657 			} ZEND_HASH_FOREACH_END();
1658 			inclusive_ns_prefixes[nscount] = NULL;
1659 		} else {
1660 			php_error_docref(NULL, E_NOTICE,
1661 				"Inclusive namespace prefixes only allowed in exclusive mode.");
1662 		}
1663 	}
1664 
1665 	if (mode == 1) {
1666 		buf = xmlOutputBufferCreateFilename(file, NULL, 0);
1667 	} else {
1668 		buf = xmlAllocOutputBuffer(NULL);
1669 	}
1670 
1671     if (buf != NULL) {
1672 		ret = xmlC14NDocSaveTo(docp, nodeset, exclusive, inclusive_ns_prefixes,
1673 			with_comments, buf);
1674 	}
1675 
1676 	if (inclusive_ns_prefixes != NULL) {
1677 		efree(inclusive_ns_prefixes);
1678 	}
1679 	if (xpathobjp != NULL) {
1680 		xmlXPathFreeObject(xpathobjp);
1681 	}
1682 	if (ctxp != NULL) {
1683 		xmlXPathFreeContext(ctxp);
1684 	}
1685 
1686     if (buf == NULL || ret < 0) {
1687         RETVAL_FALSE;
1688     } else {
1689 		if (mode == 0) {
1690 #ifdef LIBXML2_NEW_BUFFER
1691 			ret = xmlOutputBufferGetSize(buf);
1692 #else
1693 			ret = buf->buffer->use;
1694 #endif
1695 			if (ret > 0) {
1696 #ifdef LIBXML2_NEW_BUFFER
1697 				RETVAL_STRINGL((char *) xmlOutputBufferGetContent(buf), ret);
1698 #else
1699 				RETVAL_STRINGL((char *) buf->buffer->content, ret);
1700 #endif
1701 			} else {
1702 				RETVAL_EMPTY_STRING();
1703 			}
1704 		}
1705     }
1706 
1707 	if (buf) {
1708 		int bytes;
1709 
1710 		bytes = xmlOutputBufferClose(buf);
1711 		if (mode == 1 && (ret >= 0)) {
1712 			RETURN_LONG(bytes);
1713 		}
1714 	}
1715 }
1716 /* }}} */
1717 
1718 /* {{{ Canonicalize nodes to a string */
PHP_METHOD(DOMNode,C14N)1719 PHP_METHOD(DOMNode, C14N)
1720 {
1721 	dom_canonicalization(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1722 }
1723 /* }}} */
1724 
1725 /* {{{ Canonicalize nodes to a file */
PHP_METHOD(DOMNode,C14NFile)1726 PHP_METHOD(DOMNode, C14NFile)
1727 {
1728 	dom_canonicalization(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1729 }
1730 /* }}} */
1731 
1732 /* {{{ Gets an xpath for a node */
PHP_METHOD(DOMNode,getNodePath)1733 PHP_METHOD(DOMNode, getNodePath)
1734 {
1735 	zval *id;
1736 	xmlNode *nodep;
1737 	dom_object *intern;
1738 	char *value;
1739 
1740 	if (zend_parse_parameters_none() == FAILURE) {
1741 		RETURN_THROWS();
1742 	}
1743 
1744 	DOM_GET_THIS_OBJ(nodep, id, xmlNodePtr, intern);
1745 
1746 	value = (char *) xmlGetNodePath(nodep);
1747 	if (value == NULL) {
1748 		/* TODO Research if can return empty string */
1749 		RETURN_NULL();
1750 	} else {
1751 		RETVAL_STRING(value);
1752 		xmlFree(value);
1753 	}
1754 }
1755 /* }}} */
1756 
1757 /* {{{ Gets line number for a node */
PHP_METHOD(DOMNode,getLineNo)1758 PHP_METHOD(DOMNode, getLineNo)
1759 {
1760 	zval *id;
1761 	xmlNode *nodep;
1762 	dom_object *intern;
1763 
1764 	if (zend_parse_parameters_none() == FAILURE) {
1765 		RETURN_THROWS();
1766 	}
1767 
1768 	DOM_GET_THIS_OBJ(nodep, id, xmlNodePtr, intern);
1769 
1770 	RETURN_LONG(xmlGetLineNo(nodep));
1771 }
1772 /* }}} */
1773 
1774 #endif
1775