xref: /PHP-5.4/ext/simplexml/simplexml.c (revision c575ab0c)
1 /*
2   +----------------------------------------------------------------------+
3   | PHP Version 5                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2014 The PHP Group                                |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 3.01 of the PHP license,      |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available through the world-wide-web at the following url:           |
10   | http://www.php.net/license/3_01.txt                                  |
11   | If you did not receive a copy of the PHP license and are unable to   |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@php.net so we can mail you a copy immediately.               |
14   +----------------------------------------------------------------------+
15   | Authors: Sterling Hughes <sterling@php.net>                          |
16   |          Marcus Boerger <helly@php.net>                              |
17   |          Rob Richards <rrichards@php.net>                            |
18   +----------------------------------------------------------------------+
19 */
20 
21 /* $Id: 16070fc92ad6f69cebb2d52ad3f02794f833ce39 $ */
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #include "php.h"
28 #if HAVE_LIBXML && HAVE_SIMPLEXML
29 
30 #include "php_ini.h"
31 #include "ext/standard/info.h"
32 #include "ext/standard/php_string.h"
33 #include "php_simplexml.h"
34 #include "php_simplexml_exports.h"
35 #include "zend_exceptions.h"
36 #include "zend_interfaces.h"
37 #include "sxe.h"
38 
39 #define SXE_ELEMENT_BY_NAME 0
40 
41 zend_class_entry *sxe_class_entry = NULL;
42 
sxe_get_element_class_entry()43 PHP_SXE_API zend_class_entry *sxe_get_element_class_entry() /* {{{ */
44 {
45 	return sxe_class_entry;
46 }
47 /* }}} */
48 
49 #define SXE_ME(func, arg_info, flags) PHP_ME(simplexml_element, func, arg_info, flags)
50 #define SXE_MALIAS(func, alias, arg_info, flags) PHP_MALIAS(simplexml_element, func, alias, arg_info, flags)
51 
52 #define SXE_METHOD(func) PHP_METHOD(simplexml_element, func)
53 
54 static php_sxe_object* php_sxe_object_new(zend_class_entry *ce TSRMLS_DC);
55 static zend_object_value php_sxe_register_object(php_sxe_object * TSRMLS_DC);
56 static xmlNodePtr php_sxe_reset_iterator(php_sxe_object *sxe, int use_data TSRMLS_DC);
57 static xmlNodePtr php_sxe_iterator_fetch(php_sxe_object *sxe, xmlNodePtr node, int use_data TSRMLS_DC);
58 static zval *sxe_get_value(zval *z TSRMLS_DC);
59 static void php_sxe_iterator_dtor(zend_object_iterator *iter TSRMLS_DC);
60 static int php_sxe_iterator_valid(zend_object_iterator *iter TSRMLS_DC);
61 static void php_sxe_iterator_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC);
62 static int php_sxe_iterator_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC);
63 static void php_sxe_iterator_move_forward(zend_object_iterator *iter TSRMLS_DC);
64 static void php_sxe_iterator_rewind(zend_object_iterator *iter TSRMLS_DC);
65 
66 /* {{{ _node_as_zval()
67  */
_node_as_zval(php_sxe_object * sxe,xmlNodePtr node,zval * value,SXE_ITER itertype,char * name,const xmlChar * nsprefix,int isprefix TSRMLS_DC)68 static void _node_as_zval(php_sxe_object *sxe, xmlNodePtr node, zval *value, SXE_ITER itertype, char *name, const xmlChar *nsprefix, int isprefix TSRMLS_DC)
69 {
70 	php_sxe_object *subnode;
71 
72 	subnode = php_sxe_object_new(sxe->zo.ce TSRMLS_CC);
73 	subnode->document = sxe->document;
74 	subnode->document->refcount++;
75 	subnode->iter.type = itertype;
76 	if (name) {
77 		subnode->iter.name = xmlStrdup((xmlChar *)name);
78 	}
79 	if (nsprefix && *nsprefix) {
80 		subnode->iter.nsprefix = xmlStrdup(nsprefix);
81 		subnode->iter.isprefix = isprefix;
82 	}
83 
84 	php_libxml_increment_node_ptr((php_libxml_node_object *)subnode, node, NULL TSRMLS_CC);
85 
86 	value->type = IS_OBJECT;
87 	value->value.obj = php_sxe_register_object(subnode TSRMLS_CC);
88 }
89 /* }}} */
90 
91 #define APPEND_PREV_ELEMENT(__c, __v) \
92 	if ((__c) == 1) { \
93 		array_init(return_value); \
94 		add_next_index_zval(return_value, __v); \
95 	}
96 
97 #define APPEND_CUR_ELEMENT(__c, __v) \
98 	if (++(__c) > 1) { \
99 		add_next_index_zval(return_value, __v); \
100 	}
101 
102 #define GET_NODE(__s, __n) { \
103 	if ((__s)->node && (__s)->node->node) { \
104 		__n = (__s)->node->node; \
105 	} else { \
106 		__n = NULL; \
107 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Node no longer exists"); \
108 	} \
109 }
110 
php_sxe_get_first_node(php_sxe_object * sxe,xmlNodePtr node TSRMLS_DC)111 static xmlNodePtr php_sxe_get_first_node(php_sxe_object *sxe, xmlNodePtr node TSRMLS_DC) /* {{{ */
112 {
113 	php_sxe_object *intern;
114 	xmlNodePtr retnode = NULL;
115 
116 	if (sxe && sxe->iter.type != SXE_ITER_NONE) {
117 		php_sxe_reset_iterator(sxe, 1 TSRMLS_CC);
118 		if (sxe->iter.data) {
119 			intern = (php_sxe_object *)zend_object_store_get_object(sxe->iter.data TSRMLS_CC);
120 			GET_NODE(intern, retnode)
121 		}
122 		return retnode;
123 	} else {
124 		return node;
125 	}
126 }
127 /* }}} */
128 
match_ns(php_sxe_object * sxe,xmlNodePtr node,xmlChar * name,int prefix)129 static inline int match_ns(php_sxe_object *sxe, xmlNodePtr node, xmlChar *name, int prefix) /* {{{ */
130 {
131 	if (name == NULL && (node->ns == NULL || node->ns->prefix == NULL)) {
132 		return 1;
133 	}
134 
135 	if (node->ns && !xmlStrcmp(prefix ? node->ns->prefix : node->ns->href, name)) {
136 		return 1;
137 	}
138 
139 	return 0;
140 }
141 /* }}} */
142 
sxe_get_element_by_offset(php_sxe_object * sxe,long offset,xmlNodePtr node,long * cnt)143 static xmlNodePtr sxe_get_element_by_offset(php_sxe_object *sxe, long offset, xmlNodePtr node, long *cnt) /* {{{ */
144 {
145 	long nodendx = 0;
146 
147 	if (sxe->iter.type == SXE_ITER_NONE) {
148 		if (offset == 0) {
149 			if (cnt) {
150 				*cnt = 0;
151 			}
152 			return node;
153 		} else {
154 			return NULL;
155 		}
156 	}
157 	while (node && nodendx <= offset) {
158 		SKIP_TEXT(node)
159 		if (node->type == XML_ELEMENT_NODE && match_ns(sxe, node, sxe->iter.nsprefix, sxe->iter.isprefix)) {
160 			if (sxe->iter.type == SXE_ITER_CHILD || (
161 				sxe->iter.type == SXE_ITER_ELEMENT && !xmlStrcmp(node->name, sxe->iter.name))) {
162 				if (nodendx == offset) {
163 					break;
164 				}
165 				nodendx++;
166 			}
167 		}
168 next_iter:
169 		node = node->next;
170 	}
171 
172 	if (cnt) {
173 		*cnt = nodendx;
174 	}
175 
176 	return node;
177 }
178 /* }}} */
179 
sxe_find_element_by_name(php_sxe_object * sxe,xmlNodePtr node,xmlChar * name TSRMLS_DC)180 static xmlNodePtr sxe_find_element_by_name(php_sxe_object *sxe, xmlNodePtr node, xmlChar *name TSRMLS_DC) /* {{{ */
181 {
182 	while (node) {
183 		SKIP_TEXT(node)
184 		if (node->type == XML_ELEMENT_NODE && match_ns(sxe, node, sxe->iter.nsprefix, sxe->iter.isprefix)) {
185 			if (!xmlStrcmp(node->name, name)) {
186 				return node;
187 			}
188 		}
189 next_iter:
190 		node = node->next;
191 	}
192 	return NULL;
193 } /* }}} */
194 
sxe_get_element_by_name(php_sxe_object * sxe,xmlNodePtr node,char ** name,SXE_ITER * type TSRMLS_DC)195 static xmlNodePtr sxe_get_element_by_name(php_sxe_object *sxe, xmlNodePtr node, char **name, SXE_ITER *type TSRMLS_DC) /* {{{ */
196 {
197 	int         orgtype;
198 	xmlNodePtr  orgnode = node;
199 	xmlNodePtr  retnode = NULL;
200 
201 	if (sxe->iter.type != SXE_ITER_ATTRLIST)
202 	{
203 		orgtype = sxe->iter.type;
204 		if (sxe->iter.type == SXE_ITER_NONE) {
205 			sxe->iter.type = SXE_ITER_CHILD;
206 		}
207 		node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
208 		sxe->iter.type = orgtype;
209 	}
210 
211 	if (sxe->iter.type == SXE_ITER_ELEMENT) {
212 		orgnode = sxe_find_element_by_name(sxe, node, sxe->iter.name TSRMLS_CC);
213 		if (!orgnode) {
214 			return NULL;
215 		}
216 		node = orgnode->children;
217 	}
218 
219 	while (node) {
220 		SKIP_TEXT(node)
221 		if (node->type == XML_ELEMENT_NODE && match_ns(sxe, node, sxe->iter.nsprefix, sxe->iter.isprefix)) {
222 			if (!xmlStrcmp(node->name, (xmlChar *)*name)) {
223 				if (1||retnode)
224 				{
225 					*type = SXE_ITER_ELEMENT;
226 					return orgnode;
227 				}
228 				retnode = node;
229 			}
230 		}
231 next_iter:
232 		node = node->next;
233 	}
234 
235 	if (retnode)
236 	{
237 		*type = SXE_ITER_NONE;
238 		*name = NULL;
239 		return retnode;
240 	}
241 
242 	return NULL;
243 }
244 /* }}} */
245 
246 /* {{{ sxe_prop_dim_read()
247  */
sxe_prop_dim_read(zval * object,zval * member,zend_bool elements,zend_bool attribs,int type TSRMLS_DC)248 static zval * sxe_prop_dim_read(zval *object, zval *member, zend_bool elements, zend_bool attribs, int type TSRMLS_DC)
249 {
250 	zval           *return_value;
251 	php_sxe_object *sxe;
252 	char           *name;
253 	xmlNodePtr      node;
254 	xmlAttrPtr      attr = NULL;
255 	zval            tmp_zv;
256 	int             nodendx = 0;
257 	int             test = 0;
258 
259 	sxe = php_sxe_fetch_object(object TSRMLS_CC);
260 
261 	if (!member || Z_TYPE_P(member) == IS_LONG) {
262 		if (sxe->iter.type != SXE_ITER_ATTRLIST) {
263 			attribs = 0;
264 			elements = 1;
265 		} else if (!member) {
266 			/* This happens when the user did: $sxe[]->foo = $value */
267 			php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot create unnamed attribute");
268 			return NULL;
269 		}
270 		name = NULL;
271 	} else {
272 		if (Z_TYPE_P(member) != IS_STRING) {
273 			tmp_zv = *member;
274 			zval_copy_ctor(&tmp_zv);
275 			member = &tmp_zv;
276 			convert_to_string(member);
277 		}
278 		name = Z_STRVAL_P(member);
279 	}
280 
281 	GET_NODE(sxe, node);
282 
283 	if (sxe->iter.type == SXE_ITER_ATTRLIST) {
284 		attribs = 1;
285 		elements = 0;
286 		node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
287 		attr = (xmlAttrPtr)node;
288 		test = sxe->iter.name != NULL;
289 	} else if (sxe->iter.type != SXE_ITER_CHILD) {
290 		node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
291 		attr = node ? node->properties : NULL;
292 		test = 0;
293 		if (!member && node && node->parent &&
294 		    node->parent->type == XML_DOCUMENT_NODE) {
295 			/* This happens when the user did: $sxe[]->foo = $value */
296 			php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot create unnamed attribute");
297 			return NULL;
298 		}
299 	}
300 
301 	MAKE_STD_ZVAL(return_value);
302 	ZVAL_NULL(return_value);
303 
304 	if (node) {
305 		if (attribs) {
306 			if (Z_TYPE_P(member) != IS_LONG || sxe->iter.type == SXE_ITER_ATTRLIST) {
307 				if (Z_TYPE_P(member) == IS_LONG) {
308 					while (attr && nodendx <= Z_LVAL_P(member)) {
309 						if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
310 							if (nodendx == Z_LVAL_P(member)) {
311 								_node_as_zval(sxe, (xmlNodePtr) attr, return_value, SXE_ITER_NONE, NULL, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC);
312 								break;
313 							}
314 							nodendx++;
315 						}
316 						attr = attr->next;
317 					}
318 				} else {
319 					while (attr) {
320 						if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && !xmlStrcmp(attr->name, (xmlChar *)name) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
321 							_node_as_zval(sxe, (xmlNodePtr) attr, return_value, SXE_ITER_NONE, NULL, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC);
322 							break;
323 						}
324 						attr = attr->next;
325 					}
326 				}
327 			}
328 		}
329 
330 		if (elements) {
331 			if (!sxe->node) {
332 				php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, node, NULL TSRMLS_CC);
333 			}
334 			if (!member || Z_TYPE_P(member) == IS_LONG) {
335 				long cnt = 0;
336 				xmlNodePtr mynode = node;
337 
338 				if (sxe->iter.type == SXE_ITER_CHILD) {
339 					node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
340 				}
341 				if (sxe->iter.type == SXE_ITER_NONE) {
342 					if (member && Z_LVAL_P(member) > 0) {
343 						php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element %s number %ld when only 0 such elements exist", mynode->name, Z_LVAL_P(member));
344 					}
345 				} else if (member) {
346 					node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, &cnt);
347 				} else {
348 					node = NULL;
349 				}
350 				if (node) {
351 					_node_as_zval(sxe, node, return_value, SXE_ITER_NONE, NULL, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC);
352 				} else if (type == BP_VAR_W || type == BP_VAR_RW) {
353 					if (member && cnt < Z_LVAL_P(member)) {
354 						php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element %s number %ld when only %ld such elements exist", mynode->name, Z_LVAL_P(member), cnt);
355 					}
356 					node = xmlNewTextChild(mynode->parent, mynode->ns, mynode->name, NULL);
357 					_node_as_zval(sxe, node, return_value, SXE_ITER_NONE, NULL, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC);
358 				}
359 			} else {
360 #if SXE_ELEMENT_BY_NAME
361 				int newtype;
362 
363 				GET_NODE(sxe, node);
364 				node = sxe_get_element_by_name(sxe, node, &name, &newtype TSRMLS_CC);
365 				if (node) {
366 					_node_as_zval(sxe, node, return_value, newtype, name, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC);
367 				}
368 #else
369 				_node_as_zval(sxe, node, return_value, SXE_ITER_ELEMENT, name, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC);
370 #endif
371 			}
372 		}
373 	}
374 
375 	Z_SET_REFCOUNT_P(return_value, 0);
376 	Z_UNSET_ISREF_P(return_value);
377 
378 	if (member == &tmp_zv) {
379 		zval_dtor(&tmp_zv);
380 	}
381 	if (Z_TYPE_P(return_value) == IS_NULL) {
382 		FREE_ZVAL(return_value);
383 		return_value = &EG(uninitialized_zval);
384 	}
385 
386 	return return_value;
387 }
388 /* }}} */
389 
390 /* {{{ sxe_property_read()
391  */
sxe_property_read(zval * object,zval * member,int type,const zend_literal * key TSRMLS_DC)392 static zval * sxe_property_read(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC)
393 {
394 	return sxe_prop_dim_read(object, member, 1, 0, type TSRMLS_CC);
395 }
396 /* }}} */
397 
398 /* {{{ sxe_dimension_read()
399  */
sxe_dimension_read(zval * object,zval * offset,int type TSRMLS_DC)400 static zval * sxe_dimension_read(zval *object, zval *offset, int type TSRMLS_DC)
401 {
402 	return sxe_prop_dim_read(object, offset, 0, 1, type TSRMLS_CC);
403 }
404 /* }}} */
405 
406 /* {{{ change_node_zval()
407  */
change_node_zval(xmlNodePtr node,zval * value TSRMLS_DC)408 static void change_node_zval(xmlNodePtr node, zval *value TSRMLS_DC)
409 {
410 	zval value_copy;
411 	xmlChar *buffer;
412 	int buffer_len;
413 
414 	if (!value)
415 	{
416 		xmlNodeSetContentLen(node, (xmlChar *)"", 0);
417 		return;
418 	}
419 	switch (Z_TYPE_P(value)) {
420 		case IS_LONG:
421 		case IS_BOOL:
422 		case IS_DOUBLE:
423 		case IS_NULL:
424 			if (Z_REFCOUNT_P(value) > 1) {
425 				value_copy = *value;
426 				zval_copy_ctor(&value_copy);
427 				value = &value_copy;
428 			}
429 			convert_to_string(value);
430 			/* break missing intentionally */
431 		case IS_STRING:
432 			buffer = xmlEncodeEntitiesReentrant(node->doc, (xmlChar *)Z_STRVAL_P(value));
433 			buffer_len = xmlStrlen(buffer);
434 			/* check for NULL buffer in case of memory error in xmlEncodeEntitiesReentrant */
435 			if (buffer) {
436 				xmlNodeSetContentLen(node, buffer, buffer_len);
437 				xmlFree(buffer);
438 			}
439 			if (value == &value_copy) {
440 				zval_dtor(value);
441 			}
442 			break;
443 		default:
444 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "It is not possible to assign complex types to nodes");
445 			break;
446 	}
447 }
448 /* }}} */
449 
450 /* {{{ sxe_property_write()
451  */
sxe_prop_dim_write(zval * object,zval * member,zval * value,zend_bool elements,zend_bool attribs,xmlNodePtr * pnewnode TSRMLS_DC)452 static int sxe_prop_dim_write(zval *object, zval *member, zval *value, zend_bool elements, zend_bool attribs, xmlNodePtr *pnewnode TSRMLS_DC)
453 {
454 	php_sxe_object *sxe;
455 	xmlNodePtr      node;
456 	xmlNodePtr      newnode = NULL;
457 	xmlNodePtr      mynode;
458 	xmlNodePtr		tempnode;
459 	xmlAttrPtr      attr = NULL;
460 	int             counter = 0;
461 	int             is_attr = 0;
462 	int				nodendx = 0;
463 	int             test = 0;
464 	int				new_value = 0;
465 	long            cnt = 0;
466 	int				retval = SUCCESS;
467 	zval            tmp_zv, trim_zv, value_copy;
468 
469 	sxe = php_sxe_fetch_object(object TSRMLS_CC);
470 
471 	if (!member || Z_TYPE_P(member) == IS_LONG) {
472 		if (sxe->iter.type != SXE_ITER_ATTRLIST) {
473 			attribs = 0;
474 			elements = 1;
475 		} else if (!member) {
476 			/* This happens when the user did: $sxe[] = $value
477 			 * and could also be E_PARSE, but we use this only during parsing
478 			 * and this is during runtime.
479 			 */
480 			php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot create unnamed attribute");
481 			return FAILURE;
482 		}
483 	} else {
484 		if (Z_TYPE_P(member) != IS_STRING) {
485 			trim_zv = *member;
486 			zval_copy_ctor(&trim_zv);
487 			convert_to_string(&trim_zv);
488 			php_trim(Z_STRVAL(trim_zv), Z_STRLEN(trim_zv), NULL, 0, &tmp_zv, 3 TSRMLS_CC);
489 			zval_dtor(&trim_zv);
490 			member = &tmp_zv;
491 		}
492 
493 		if (!Z_STRLEN_P(member)) {
494 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot write or create unnamed %s", attribs ? "attribute" : "element");
495 			if (member == &tmp_zv) {
496 				zval_dtor(&tmp_zv);
497 			}
498 			return FAILURE;
499 		}
500 	}
501 
502 	GET_NODE(sxe, node);
503 
504 	if (sxe->iter.type == SXE_ITER_ATTRLIST) {
505 		attribs = 1;
506 		elements = 0;
507 		node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
508 		attr = (xmlAttrPtr)node;
509 		test = sxe->iter.name != NULL;
510 	} else if (sxe->iter.type != SXE_ITER_CHILD) {
511 		mynode = node;
512 		node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
513 		attr = node ? node->properties : NULL;
514 		test = 0;
515 		if (!member && node && node->parent &&
516 		    node->parent->type == XML_DOCUMENT_NODE) {
517 			/* This happens when the user did: $sxe[] = $value
518 			 * and could also be E_PARSE, but we use this only during parsing
519 			 * and this is during runtime.
520 			 */
521 			php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot create unnamed attribute");
522 			return FAILURE;
523 		}
524 		if (attribs && !node && sxe->iter.type == SXE_ITER_ELEMENT) {
525 			node = xmlNewChild(mynode, mynode->ns, sxe->iter.name, NULL);
526 			attr = node->properties;
527 		}
528 	}
529 
530 	mynode = node;
531 
532 	if (value) {
533 		switch (Z_TYPE_P(value)) {
534 			case IS_LONG:
535 			case IS_BOOL:
536 			case IS_DOUBLE:
537 			case IS_NULL:
538 				if (Z_REFCOUNT_P(value) > 1) {
539 					value_copy = *value;
540 					zval_copy_ctor(&value_copy);
541 					value = &value_copy;
542 				}
543 				convert_to_string(value);
544 				break;
545 			case IS_STRING:
546 				break;
547 			case IS_OBJECT:
548 				if (Z_OBJCE_P(value) == sxe_class_entry) {
549 					value = sxe_get_value(value TSRMLS_CC);
550 					INIT_PZVAL(value);
551 					new_value = 1;
552 					break;
553 				}
554 				/* break is missing intentionally */
555 			default:
556 				if (member == &tmp_zv) {
557 					zval_dtor(&tmp_zv);
558 				}
559 				zend_error(E_WARNING, "It is not yet possible to assign complex types to %s", attribs ? "attributes" : "properties");
560 				return FAILURE;
561 		}
562 	}
563 
564 	if (node) {
565 		if (attribs) {
566 			if (Z_TYPE_P(member) == IS_LONG) {
567 				while (attr && nodendx <= Z_LVAL_P(member)) {
568 					if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
569 						if (nodendx == Z_LVAL_P(member)) {
570 							is_attr = 1;
571 							++counter;
572 							break;
573 						}
574 						nodendx++;
575 					}
576 					attr = attr->next;
577 				}
578 			} else {
579 				while (attr) {
580 					if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && !xmlStrcmp(attr->name, (xmlChar *)Z_STRVAL_P(member)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
581 						is_attr = 1;
582 						++counter;
583 						break;
584 					}
585 					attr = attr->next;
586 				}
587 			}
588 
589 		}
590 
591 		if (elements) {
592 			if (!member || Z_TYPE_P(member) == IS_LONG) {
593 				if (node->type == XML_ATTRIBUTE_NODE) {
594 					php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot create duplicate attribute");
595 					return FAILURE;
596 				}
597 
598 				if (sxe->iter.type == SXE_ITER_NONE) {
599 					newnode = node;
600 					++counter;
601 					if (member && Z_LVAL_P(member) > 0) {
602 						php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element %s number %ld when only 0 such elements exist", mynode->name, Z_LVAL_P(member));
603 						retval = FAILURE;
604 					}
605 				} else if (member) {
606 					newnode = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, &cnt);
607 					if (newnode) {
608 						++counter;
609 					}
610 				}
611 			} else {
612 				node = node->children;
613 				while (node) {
614 					SKIP_TEXT(node);
615 
616 					if (!xmlStrcmp(node->name, (xmlChar *)Z_STRVAL_P(member))) {
617 						newnode = node;
618 						++counter;
619 					}
620 
621 next_iter:
622 					node = node->next;
623 				}
624 			}
625 		}
626 
627 		if (counter == 1) {
628 			if (is_attr) {
629 				newnode = (xmlNodePtr) attr;
630 			}
631 			if (value) {
632 				while ((tempnode = (xmlNodePtr) newnode->children)) {
633 					xmlUnlinkNode(tempnode);
634 					php_libxml_node_free_resource((xmlNodePtr) tempnode TSRMLS_CC);
635 				}
636 				change_node_zval(newnode, value TSRMLS_CC);
637 			}
638 		} else if (counter > 1) {
639 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot assign to an array of nodes (duplicate subnodes or attr detected)");
640 			retval = FAILURE;
641 		} else if (elements) {
642 			if (!node) {
643 				if (!member || Z_TYPE_P(member) == IS_LONG) {
644 					newnode = xmlNewTextChild(mynode->parent, mynode->ns, mynode->name, value ? (xmlChar *)Z_STRVAL_P(value) : NULL);
645 				} else {
646 					newnode = xmlNewTextChild(mynode, mynode->ns, (xmlChar *)Z_STRVAL_P(member), value ? (xmlChar *)Z_STRVAL_P(value) : NULL);
647 				}
648 			} else if (!member || Z_TYPE_P(member) == IS_LONG) {
649 				if (member && cnt < Z_LVAL_P(member)) {
650 					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element %s number %ld when only %ld such elements exist", mynode->name, Z_LVAL_P(member), cnt);
651 					retval = FAILURE;
652 				}
653 				newnode = xmlNewTextChild(mynode->parent, mynode->ns, mynode->name, value ? (xmlChar *)Z_STRVAL_P(value) : NULL);
654 			}
655 		} else if (attribs) {
656 			if (Z_TYPE_P(member) == IS_LONG) {
657 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot change attribute number %ld when only %d attributes exist", Z_LVAL_P(member), nodendx);
658 				retval = FAILURE;
659 			} else {
660 				newnode = (xmlNodePtr)xmlNewProp(node, (xmlChar *)Z_STRVAL_P(member), value ? (xmlChar *)Z_STRVAL_P(value) : NULL);
661 			}
662 		}
663 	}
664 
665 	if (member == &tmp_zv) {
666 		zval_dtor(&tmp_zv);
667 	}
668 	if (pnewnode) {
669 		*pnewnode = newnode;
670 	}
671 	if (value && value == &value_copy) {
672 		zval_dtor(value);
673 	}
674 	if (new_value) {
675 		zval_ptr_dtor(&value);
676 	}
677 	return retval;
678 }
679 /* }}} */
680 
681 /* {{{ sxe_property_write()
682  */
sxe_property_write(zval * object,zval * member,zval * value,const zend_literal * key TSRMLS_DC)683 static void sxe_property_write(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC)
684 {
685 	sxe_prop_dim_write(object, member, value, 1, 0, NULL TSRMLS_CC);
686 }
687 /* }}} */
688 
689 /* {{{ sxe_dimension_write()
690  */
sxe_dimension_write(zval * object,zval * offset,zval * value TSRMLS_DC)691 static void sxe_dimension_write(zval *object, zval *offset, zval *value TSRMLS_DC)
692 {
693 	sxe_prop_dim_write(object, offset, value, 0, 1, NULL TSRMLS_CC);
694 }
695 /* }}} */
696 
sxe_property_get_adr(zval * object,zval * member,const zend_literal * key TSRMLS_DC)697 static zval** sxe_property_get_adr(zval *object, zval *member, const zend_literal *key TSRMLS_DC) /* {{{ */
698 {
699 	php_sxe_object *sxe;
700 	xmlNodePtr      node;
701 	zval           *return_value;
702 	char           *name;
703 	SXE_ITER        type;
704 
705 	sxe = php_sxe_fetch_object(object TSRMLS_CC);
706 
707 	GET_NODE(sxe, node);
708 	convert_to_string(member);
709 	name = Z_STRVAL_P(member);
710 	node = sxe_get_element_by_name(sxe, node, &name, &type TSRMLS_CC);
711 	if (node) {
712 		return NULL;
713 	}
714 	if (sxe_prop_dim_write(object, member, NULL, 1, 0, &node TSRMLS_CC) != SUCCESS) {
715 		return NULL;
716 	}
717 	type = SXE_ITER_NONE;
718 	name = NULL;
719 
720 	MAKE_STD_ZVAL(return_value);
721 	_node_as_zval(sxe, node, return_value, type, name, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC);
722 
723 	sxe = php_sxe_fetch_object(return_value TSRMLS_CC);
724 	if (sxe->tmp) {
725 		zval_ptr_dtor(&sxe->tmp);
726 	}
727 	sxe->tmp = return_value;
728 	Z_SET_ISREF_P(return_value);
729 
730 	return &sxe->tmp;
731 }
732 /* }}} */
733 
734 /* {{{ sxe_prop_dim_exists()
735  */
sxe_prop_dim_exists(zval * object,zval * member,int check_empty,zend_bool elements,zend_bool attribs TSRMLS_DC)736 static int sxe_prop_dim_exists(zval *object, zval *member, int check_empty, zend_bool elements, zend_bool attribs TSRMLS_DC)
737 {
738 	php_sxe_object *sxe;
739 	xmlNodePtr      node;
740 	xmlAttrPtr      attr = NULL;
741 	int				exists = 0;
742 	int             test = 0;
743 	zval            tmp_zv;
744 
745 	if (Z_TYPE_P(member) != IS_STRING && Z_TYPE_P(member) != IS_LONG) {
746 		tmp_zv = *member;
747 		zval_copy_ctor(&tmp_zv);
748 		member = &tmp_zv;
749 		convert_to_string(member);
750 	}
751 
752 	sxe = php_sxe_fetch_object(object TSRMLS_CC);
753 
754 	GET_NODE(sxe, node);
755 
756 	if (Z_TYPE_P(member) == IS_LONG) {
757 		if (sxe->iter.type != SXE_ITER_ATTRLIST) {
758 			attribs = 0;
759 			elements = 1;
760 			if (sxe->iter.type == SXE_ITER_CHILD) {
761 				node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
762 			}
763 		}
764 	}
765 
766 	if (sxe->iter.type == SXE_ITER_ATTRLIST) {
767 		attribs = 1;
768 		elements = 0;
769 		node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
770 		attr = (xmlAttrPtr)node;
771 		test = sxe->iter.name != NULL;
772 	} else if (sxe->iter.type != SXE_ITER_CHILD) {
773 		node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
774 		attr = node ? node->properties : NULL;
775 		test = 0;
776 	}
777 
778 	if (node) {
779 		if (attribs) {
780 			if (Z_TYPE_P(member) == IS_LONG) {
781 				int	nodendx = 0;
782 
783 				while (attr && nodendx <= Z_LVAL_P(member)) {
784 					if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
785 						if (nodendx == Z_LVAL_P(member)) {
786 							exists = 1;
787 							break;
788 						}
789 						nodendx++;
790 					}
791 					attr = attr->next;
792 				}
793 			} else {
794 				while (attr) {
795 					if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && !xmlStrcmp(attr->name, (xmlChar *)Z_STRVAL_P(member)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
796 						exists = 1;
797 						break;
798 					}
799 
800 					attr = attr->next;
801 				}
802 			}
803 			if (exists && check_empty == 1 &&
804 				(!attr->children || !attr->children->content || !attr->children->content[0] || !xmlStrcmp(attr->children->content, "0")) ) {
805 				/* Attribute with no content in it's text node */
806 				exists = 0;
807 			}
808 		}
809 
810 		if (elements) {
811 			if (Z_TYPE_P(member) == IS_LONG) {
812 				if (sxe->iter.type == SXE_ITER_CHILD) {
813 					node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
814 				}
815 				node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, NULL);
816 			}
817 			else {
818 				node = node->children;
819 				while (node) {
820 					xmlNodePtr nnext;
821 					nnext = node->next;
822 					if ((node->type == XML_ELEMENT_NODE) && !xmlStrcmp(node->name, (xmlChar *)Z_STRVAL_P(member))) {
823 						break;
824 					}
825 					node = nnext;
826 				}
827 			}
828 			if (node) {
829 				exists = 1;
830                                 if (check_empty == 1 &&
831 					(!node->children || (node->children->type == XML_TEXT_NODE && !node->children->next &&
832 						(!node->children->content || !node->children->content[0] || !xmlStrcmp(node->children->content, "0")))) ) {
833 					exists = 0;
834 				}
835 			}
836 		}
837 	}
838 
839 	if (member == &tmp_zv) {
840 		zval_dtor(&tmp_zv);
841 	}
842 
843 	return exists;
844 }
845 /* }}} */
846 
847 /* {{{ sxe_property_exists()
848  */
sxe_property_exists(zval * object,zval * member,int check_empty,const zend_literal * key TSRMLS_DC)849 static int sxe_property_exists(zval *object, zval *member, int check_empty, const zend_literal *key TSRMLS_DC)
850 {
851 	return sxe_prop_dim_exists(object, member, check_empty, 1, 0 TSRMLS_CC);
852 }
853 /* }}} */
854 
855 /* {{{ sxe_property_exists()
856  */
sxe_dimension_exists(zval * object,zval * member,int check_empty TSRMLS_DC)857 static int sxe_dimension_exists(zval *object, zval *member, int check_empty TSRMLS_DC)
858 {
859 	return sxe_prop_dim_exists(object, member, check_empty, 0, 1 TSRMLS_CC);
860 }
861 /* }}} */
862 
863 /* {{{ sxe_prop_dim_delete()
864  */
sxe_prop_dim_delete(zval * object,zval * member,zend_bool elements,zend_bool attribs TSRMLS_DC)865 static void sxe_prop_dim_delete(zval *object, zval *member, zend_bool elements, zend_bool attribs TSRMLS_DC)
866 {
867 	php_sxe_object *sxe;
868 	xmlNodePtr      node;
869 	xmlNodePtr      nnext;
870 	xmlAttrPtr      attr = NULL;
871 	xmlAttrPtr      anext;
872 	zval            tmp_zv;
873 	int             test = 0;
874 
875 	if (Z_TYPE_P(member) != IS_STRING && Z_TYPE_P(member) != IS_LONG) {
876 		tmp_zv = *member;
877 		zval_copy_ctor(&tmp_zv);
878 		member = &tmp_zv;
879 		convert_to_string(member);
880 	}
881 
882 	sxe = php_sxe_fetch_object(object TSRMLS_CC);
883 
884 	GET_NODE(sxe, node);
885 
886 	if (Z_TYPE_P(member) == IS_LONG) {
887 		if (sxe->iter.type != SXE_ITER_ATTRLIST) {
888 			attribs = 0;
889 			elements = 1;
890 			if (sxe->iter.type == SXE_ITER_CHILD) {
891 				node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
892 			}
893 		}
894 	}
895 
896 	if (sxe->iter.type == SXE_ITER_ATTRLIST) {
897 		attribs = 1;
898 		elements = 0;
899 		node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
900 		attr = (xmlAttrPtr)node;
901 		test = sxe->iter.name != NULL;
902 	} else if (sxe->iter.type != SXE_ITER_CHILD) {
903 		node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
904 		attr = node ? node->properties : NULL;
905 		test = 0;
906 	}
907 
908 	if (node) {
909 		if (attribs) {
910 			if (Z_TYPE_P(member) == IS_LONG) {
911 				int	nodendx = 0;
912 
913 				while (attr && nodendx <= Z_LVAL_P(member)) {
914 					if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
915 						if (nodendx == Z_LVAL_P(member)) {
916 							xmlUnlinkNode((xmlNodePtr) attr);
917 							php_libxml_node_free_resource((xmlNodePtr) attr TSRMLS_CC);
918 							break;
919 						}
920 						nodendx++;
921 					}
922 					attr = attr->next;
923 				}
924 			} else {
925 				while (attr) {
926 					anext = attr->next;
927 					if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && !xmlStrcmp(attr->name, (xmlChar *)Z_STRVAL_P(member)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
928 						xmlUnlinkNode((xmlNodePtr) attr);
929 						php_libxml_node_free_resource((xmlNodePtr) attr TSRMLS_CC);
930 						break;
931 					}
932 					attr = anext;
933 				}
934 			}
935 		}
936 
937 		if (elements) {
938 			if (Z_TYPE_P(member) == IS_LONG) {
939 				if (sxe->iter.type == SXE_ITER_CHILD) {
940 					node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
941 				}
942 				node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, NULL);
943 				if (node) {
944 					xmlUnlinkNode(node);
945 					php_libxml_node_free_resource(node TSRMLS_CC);
946 				}
947 			} else {
948 				node = node->children;
949 				while (node) {
950 					nnext = node->next;
951 
952 					SKIP_TEXT(node);
953 
954 					if (!xmlStrcmp(node->name, (xmlChar *)Z_STRVAL_P(member))) {
955 						xmlUnlinkNode(node);
956 						php_libxml_node_free_resource(node TSRMLS_CC);
957 					}
958 
959 next_iter:
960 					node = nnext;
961 				}
962 			}
963 		}
964 	}
965 
966 	if (member == &tmp_zv) {
967 		zval_dtor(&tmp_zv);
968 	}
969 }
970 /* }}} */
971 
972 /* {{{ sxe_property_delete()
973  */
sxe_property_delete(zval * object,zval * member,const zend_literal * key TSRMLS_DC)974 static void sxe_property_delete(zval *object, zval *member, const zend_literal *key TSRMLS_DC)
975 {
976 	sxe_prop_dim_delete(object, member, 1, 0 TSRMLS_CC);
977 }
978 /* }}} */
979 
980 /* {{{ sxe_dimension_unset()
981  */
sxe_dimension_delete(zval * object,zval * offset TSRMLS_DC)982 static void sxe_dimension_delete(zval *object, zval *offset TSRMLS_DC)
983 {
984 	sxe_prop_dim_delete(object, offset, 0, 1 TSRMLS_CC);
985 }
986 /* }}} */
987 
sxe_xmlNodeListGetString(xmlDocPtr doc,xmlNodePtr list,int inLine)988 static inline char * sxe_xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) /* {{{ */
989 {
990 	xmlChar *tmp = xmlNodeListGetString(doc, list, inLine);
991 	char    *res;
992 
993 	if (tmp) {
994 		res = estrdup((char*)tmp);
995 		xmlFree(tmp);
996 	} else {
997 		res = STR_EMPTY_ALLOC();
998 	}
999 
1000 	return res;
1001 }
1002 /* }}} */
1003 
1004 /* {{{ _get_base_node_value()
1005  */
_get_base_node_value(php_sxe_object * sxe_ref,xmlNodePtr node,zval ** value,xmlChar * nsprefix,int isprefix TSRMLS_DC)1006 static void _get_base_node_value(php_sxe_object *sxe_ref, xmlNodePtr node, zval **value, xmlChar *nsprefix, int isprefix TSRMLS_DC)
1007 {
1008 	php_sxe_object *subnode;
1009 	xmlChar        *contents;
1010 
1011 	MAKE_STD_ZVAL(*value);
1012 
1013 	if (node->children && node->children->type == XML_TEXT_NODE && !xmlIsBlankNode(node->children)) {
1014 		contents = xmlNodeListGetString(node->doc, node->children, 1);
1015 		if (contents) {
1016 			ZVAL_STRING(*value, (char *)contents, 1);
1017 			xmlFree(contents);
1018 		}
1019 	} else {
1020 		subnode = php_sxe_object_new(sxe_ref->zo.ce TSRMLS_CC);
1021 		subnode->document = sxe_ref->document;
1022 		subnode->document->refcount++;
1023 		if (nsprefix && *nsprefix) {
1024 			subnode->iter.nsprefix = xmlStrdup((xmlChar *)nsprefix);
1025 			subnode->iter.isprefix = isprefix;
1026 		}
1027 		php_libxml_increment_node_ptr((php_libxml_node_object *)subnode, node, NULL TSRMLS_CC);
1028 
1029 		(*value)->type = IS_OBJECT;
1030 		(*value)->value.obj = php_sxe_register_object(subnode TSRMLS_CC);
1031 		/*zval_add_ref(value);*/
1032 	}
1033 }
1034 /* }}} */
1035 
sxe_properties_add(HashTable * rv,char * name,int namelen,zval * value TSRMLS_DC)1036 static void sxe_properties_add(HashTable *rv, char *name, int namelen, zval *value TSRMLS_DC) /* {{{ */
1037 {
1038 	zval  **data_ptr;
1039 	zval  *newptr;
1040 	ulong h = zend_hash_func(name, namelen);
1041 
1042 	if (zend_hash_quick_find(rv, name, namelen, h, (void **) &data_ptr) == SUCCESS) {
1043 		if (Z_TYPE_PP(data_ptr) == IS_ARRAY) {
1044 			zend_hash_next_index_insert(Z_ARRVAL_PP(data_ptr), &value, sizeof(zval *), NULL);
1045 		} else {
1046 			MAKE_STD_ZVAL(newptr);
1047 			array_init(newptr);
1048 
1049 			zval_add_ref(data_ptr);
1050 			zend_hash_next_index_insert(Z_ARRVAL_P(newptr), data_ptr, sizeof(zval *), NULL);
1051 			zend_hash_next_index_insert(Z_ARRVAL_P(newptr), &value, sizeof(zval *), NULL);
1052 
1053 			zend_hash_quick_update(rv, name, namelen, h, &newptr, sizeof(zval *), NULL);
1054 		}
1055 	} else {
1056 		zend_hash_quick_update(rv, name, namelen, h, &value, sizeof(zval *), NULL);
1057 	}
1058 }
1059 /* }}} */
1060 
sxe_get_prop_hash(zval * object,int is_debug TSRMLS_DC)1061 static HashTable * sxe_get_prop_hash(zval *object, int is_debug TSRMLS_DC) /* {{{ */
1062 {
1063 	zval            *value;
1064 	zval            *zattr;
1065 	HashTable       *rv;
1066 	php_sxe_object  *sxe;
1067 	char            *name;
1068 	xmlNodePtr       node;
1069 	xmlAttrPtr       attr;
1070 	int              namelen;
1071 	int              test;
1072 	char 		 use_iter;
1073 	zval            *iter_data = NULL;
1074 
1075 	use_iter = 0;
1076 
1077 	sxe = php_sxe_fetch_object(object TSRMLS_CC);
1078 
1079 	if (is_debug) {
1080 		ALLOC_HASHTABLE(rv);
1081 		zend_hash_init(rv, 0, NULL, ZVAL_PTR_DTOR, 0);
1082 	}
1083 	else if (sxe->properties) {
1084 		zend_hash_clean(sxe->properties);
1085 		rv = sxe->properties;
1086 	} else {
1087 		ALLOC_HASHTABLE(rv);
1088 		zend_hash_init(rv, 0, NULL, ZVAL_PTR_DTOR, 0);
1089 		sxe->properties = rv;
1090 	}
1091 
1092 	GET_NODE(sxe, node);
1093 	if (!node) {
1094 		return rv;
1095 	}
1096 	if (is_debug || sxe->iter.type != SXE_ITER_CHILD) {
1097 		if (sxe->iter.type == SXE_ITER_ELEMENT) {
1098 			node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1099 		}
1100 		if (!node || node->type != XML_ENTITY_DECL) {
1101 			attr = node ? (xmlAttrPtr)node->properties : NULL;
1102 			zattr = NULL;
1103 			test = sxe->iter.name && sxe->iter.type == SXE_ITER_ATTRLIST;
1104 			while (attr) {
1105 				if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr)attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
1106 					MAKE_STD_ZVAL(value);
1107 					ZVAL_STRING(value, sxe_xmlNodeListGetString((xmlDocPtr) sxe->document->ptr, attr->children, 1), 0);
1108 					namelen = xmlStrlen(attr->name) + 1;
1109 					if (!zattr) {
1110 						MAKE_STD_ZVAL(zattr);
1111 						array_init(zattr);
1112 						sxe_properties_add(rv, "@attributes", sizeof("@attributes"), zattr TSRMLS_CC);
1113 					}
1114 					add_assoc_zval_ex(zattr, (char*)attr->name, namelen, value);
1115 				}
1116 				attr = attr->next;
1117 			}
1118 		}
1119 	}
1120 
1121 	GET_NODE(sxe, node);
1122 	node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1123 
1124 	if (node && sxe->iter.type != SXE_ITER_ATTRLIST) {
1125 		if (node->type == XML_ATTRIBUTE_NODE) {
1126 			MAKE_STD_ZVAL(value);
1127 			ZVAL_STRING(value, sxe_xmlNodeListGetString(node->doc, node->children, 1), 0);
1128 			zend_hash_next_index_insert(rv, &value, sizeof(zval *), NULL);
1129 			node = NULL;
1130 		} else if (sxe->iter.type != SXE_ITER_CHILD) {
1131 
1132 			if ( !node->children || !node->parent || !node->next || node->children->next || node->children->children || node->parent->children == node->parent->last ) {
1133 				node = node->children;
1134 			} else {
1135 				iter_data = sxe->iter.data;
1136 				sxe->iter.data = NULL;
1137 
1138 				node = php_sxe_reset_iterator(sxe, 0 TSRMLS_CC);
1139 
1140 				use_iter = 1;
1141 			}
1142 		}
1143 
1144 		while (node) {
1145 			if (node->children != NULL || node->prev != NULL || node->next != NULL) {
1146 				SKIP_TEXT(node);
1147 			} else {
1148 				if (node->type == XML_TEXT_NODE) {
1149 					const xmlChar *cur = node->content;
1150 
1151 					if (*cur != 0) {
1152 						MAKE_STD_ZVAL(value);
1153 						ZVAL_STRING(value, sxe_xmlNodeListGetString(node->doc, node, 1), 0);
1154 						zend_hash_next_index_insert(rv, &value, sizeof(zval *), NULL);
1155 					}
1156 					goto next_iter;
1157 				}
1158 			}
1159 
1160 			if (node->type == XML_ELEMENT_NODE && (! match_ns(sxe, node, sxe->iter.nsprefix, sxe->iter.isprefix))) {
1161 				goto next_iter;
1162 			}
1163 
1164 			name = (char *) node->name;
1165 			if (!name) {
1166 				goto next_iter;
1167 			} else {
1168 				namelen = xmlStrlen(node->name) + 1;
1169 			}
1170 
1171 			_get_base_node_value(sxe, node, &value, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC);
1172 
1173 			if ( use_iter ) {
1174 				zend_hash_next_index_insert(rv, &value, sizeof(zval *), NULL);
1175 			} else {
1176 				sxe_properties_add(rv, name, namelen, value TSRMLS_CC);
1177 			}
1178 next_iter:
1179 			if ( use_iter ) {
1180 				node = php_sxe_iterator_fetch(sxe, node->next, 0 TSRMLS_CC);
1181 			} else {
1182 				node = node->next;
1183 			}
1184 		}
1185 	}
1186 
1187 	if ( use_iter ) {
1188 		if (sxe->iter.data) {
1189 			zval_ptr_dtor(&sxe->iter.data);
1190 		}
1191 		sxe->iter.data = iter_data;
1192 	}
1193 
1194 	return rv;
1195 }
1196 /* }}} */
1197 
sxe_get_gc(zval * object,zval *** table,int * n TSRMLS_DC)1198 static HashTable * sxe_get_gc(zval *object, zval ***table, int *n TSRMLS_DC) /* {{{ */ {
1199 	php_sxe_object  *sxe;
1200 	sxe = php_sxe_fetch_object(object TSRMLS_CC);
1201 
1202 	*table = NULL;
1203 	*n = 0;
1204 	return sxe->properties;
1205 }
1206 /* }}} */
1207 
sxe_get_properties(zval * object TSRMLS_DC)1208 static HashTable * sxe_get_properties(zval *object TSRMLS_DC) /* {{{ */
1209 {
1210 	return sxe_get_prop_hash(object, 0 TSRMLS_CC);
1211 }
1212 /* }}} */
1213 
sxe_get_debug_info(zval * object,int * is_temp TSRMLS_DC)1214 static HashTable * sxe_get_debug_info(zval *object, int *is_temp TSRMLS_DC) /* {{{ */
1215 {
1216 	*is_temp = 1;
1217 	return sxe_get_prop_hash(object, 1 TSRMLS_CC);
1218 }
1219 /* }}} */
1220 
sxe_objects_compare(zval * object1,zval * object2 TSRMLS_DC)1221 static int sxe_objects_compare(zval *object1, zval *object2 TSRMLS_DC) /* {{{ */
1222 {
1223 	php_sxe_object *sxe1;
1224 	php_sxe_object *sxe2;
1225 
1226 	sxe1 = php_sxe_fetch_object(object1 TSRMLS_CC);
1227 	sxe2 = php_sxe_fetch_object(object2 TSRMLS_CC);
1228 
1229 	if (sxe1->node == NULL) {
1230 		if (sxe2->node) {
1231 			return 1;
1232 		} else if (sxe1->document->ptr == sxe2->document->ptr) {
1233 			return 0;
1234 		}
1235 	} else {
1236 		return !(sxe1->node == sxe2->node);
1237 	}
1238 	return 1;
1239 }
1240 /* }}} */
1241 
1242 /* {{{ proto array SimpleXMLElement::xpath(string path)
1243    Runs XPath query on the XML data */
SXE_METHOD(xpath)1244 SXE_METHOD(xpath)
1245 {
1246 	php_sxe_object    *sxe;
1247 	zval              *value;
1248 	char              *query;
1249 	int                query_len;
1250 	int                i;
1251 	int                nsnbr = 0;
1252 	xmlNsPtr          *ns = NULL;
1253 	xmlXPathObjectPtr  retval;
1254 	xmlNodeSetPtr      result;
1255 	xmlNodePtr		   nodeptr;
1256 
1257 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &query, &query_len) == FAILURE) {
1258 		return;
1259 	}
1260 
1261 	sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1262 
1263 	if (sxe->iter.type == SXE_ITER_ATTRLIST) {
1264 		return; /* attributes don't have attributes */
1265 	}
1266 
1267 	if (!sxe->xpath) {
1268 		sxe->xpath = xmlXPathNewContext((xmlDocPtr) sxe->document->ptr);
1269 	}
1270 	if (!sxe->node) {
1271 		php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement((xmlDocPtr) sxe->document->ptr), NULL TSRMLS_CC);
1272 		if (!sxe->node) {
1273 			RETURN_FALSE;
1274 		}
1275 	}
1276 
1277 	nodeptr = php_sxe_get_first_node(sxe, sxe->node->node TSRMLS_CC);
1278 
1279 	sxe->xpath->node = nodeptr;
1280 
1281  	ns = xmlGetNsList((xmlDocPtr) sxe->document->ptr, nodeptr);
1282 	if (ns != NULL) {
1283 		while (ns[nsnbr] != NULL) {
1284 			nsnbr++;
1285 		}
1286 	}
1287 
1288 	sxe->xpath->namespaces = ns;
1289 	sxe->xpath->nsNr = nsnbr;
1290 
1291 	retval = xmlXPathEval((xmlChar *)query, sxe->xpath);
1292 	if (ns != NULL) {
1293 		xmlFree(ns);
1294 		sxe->xpath->namespaces = NULL;
1295 		sxe->xpath->nsNr = 0;
1296 	}
1297 
1298 	if (!retval) {
1299 		RETURN_FALSE;
1300 	}
1301 
1302 	result = retval->nodesetval;
1303 
1304 	array_init(return_value);
1305 
1306 	if (result != NULL) {
1307 		for (i = 0; i < result->nodeNr; ++i) {
1308 			nodeptr = result->nodeTab[i];
1309 			if (nodeptr->type == XML_TEXT_NODE || nodeptr->type == XML_ELEMENT_NODE || nodeptr->type == XML_ATTRIBUTE_NODE) {
1310 				MAKE_STD_ZVAL(value);
1311 				/**
1312 				 * Detect the case where the last selector is text(), simplexml
1313 				 * always accesses the text() child by default, therefore we assign
1314 				 * to the parent node.
1315 				 */
1316 				if (nodeptr->type == XML_TEXT_NODE) {
1317 					_node_as_zval(sxe, nodeptr->parent, value, SXE_ITER_NONE, NULL, NULL, 0 TSRMLS_CC);
1318 				} else if (nodeptr->type == XML_ATTRIBUTE_NODE) {
1319 					_node_as_zval(sxe, nodeptr->parent, value, SXE_ITER_ATTRLIST, (char*)nodeptr->name, nodeptr->ns ? (xmlChar *)nodeptr->ns->href : NULL, 0 TSRMLS_CC);
1320 				} else {
1321 					_node_as_zval(sxe, nodeptr, value, SXE_ITER_NONE, NULL, NULL, 0 TSRMLS_CC);
1322 				}
1323 
1324 				add_next_index_zval(return_value, value);
1325 			}
1326 		}
1327 	}
1328 
1329 	xmlXPathFreeObject(retval);
1330 }
1331 /* }}} */
1332 
1333 /* {{{ proto bool SimpleXMLElement::registerXPathNamespace(string prefix, string ns)
1334    Creates a prefix/ns context for the next XPath query */
SXE_METHOD(registerXPathNamespace)1335 SXE_METHOD(registerXPathNamespace)
1336 {
1337 	php_sxe_object    *sxe;
1338 	int prefix_len, ns_uri_len;
1339 	char *prefix, *ns_uri;
1340 
1341 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &prefix, &prefix_len, &ns_uri, &ns_uri_len) == FAILURE) {
1342 		return;
1343 	}
1344 
1345 	sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1346 	if (!sxe->xpath) {
1347 		sxe->xpath = xmlXPathNewContext((xmlDocPtr) sxe->document->ptr);
1348 	}
1349 
1350 	if (xmlXPathRegisterNs(sxe->xpath, (xmlChar *)prefix, (xmlChar *)ns_uri) != 0) {
1351 		RETURN_FALSE
1352 	}
1353 	RETURN_TRUE;
1354 }
1355 
1356 /* }}} */
1357 
1358 /* {{{ proto string SimpleXMLElement::asXML([string filename])
1359    Return a well-formed XML string based on SimpleXML element */
SXE_METHOD(asXML)1360 SXE_METHOD(asXML)
1361 {
1362 	php_sxe_object     *sxe;
1363 	xmlNodePtr          node;
1364 	xmlOutputBufferPtr  outbuf;
1365 	xmlChar            *strval;
1366 	int                 strval_len;
1367 	char               *filename;
1368 	int                 filename_len;
1369 
1370 	if (ZEND_NUM_ARGS() > 1) {
1371 		RETURN_FALSE;
1372 	}
1373 
1374 	if (ZEND_NUM_ARGS() == 1) {
1375 		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p", &filename, &filename_len) == FAILURE) {
1376 			RETURN_FALSE;
1377 		}
1378 
1379 		sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1380 		GET_NODE(sxe, node);
1381 		node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1382 
1383 		if (node) {
1384 			if (node->parent && (XML_DOCUMENT_NODE == node->parent->type)) {
1385 				int bytes;
1386 				bytes = xmlSaveFile(filename, (xmlDocPtr) sxe->document->ptr);
1387 				if (bytes == -1) {
1388 					RETURN_FALSE;
1389 				} else {
1390 					RETURN_TRUE;
1391 				}
1392 			} else {
1393 				outbuf = xmlOutputBufferCreateFilename(filename, NULL, 0);
1394 
1395 				if (outbuf == NULL) {
1396 					RETURN_FALSE;
1397 				}
1398 
1399 				xmlNodeDumpOutput(outbuf, (xmlDocPtr) sxe->document->ptr, node, 0, 0, NULL);
1400 				xmlOutputBufferClose(outbuf);
1401 				RETURN_TRUE;
1402 			}
1403 		} else {
1404 			RETURN_FALSE;
1405 		}
1406 	}
1407 
1408 	sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1409 	GET_NODE(sxe, node);
1410 	node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1411 
1412 	if (node) {
1413 		if (node->parent && (XML_DOCUMENT_NODE == node->parent->type)) {
1414 			xmlDocDumpMemoryEnc((xmlDocPtr) sxe->document->ptr, &strval, &strval_len, ((xmlDocPtr) sxe->document->ptr)->encoding);
1415 			RETVAL_STRINGL((char *)strval, strval_len, 1);
1416 			xmlFree(strval);
1417 		} else {
1418 			/* Should we be passing encoding information instead of NULL? */
1419 			outbuf = xmlAllocOutputBuffer(NULL);
1420 
1421 			if (outbuf == NULL) {
1422 				RETURN_FALSE;
1423 			}
1424 
1425 			xmlNodeDumpOutput(outbuf, (xmlDocPtr) sxe->document->ptr, node, 0, 0, ((xmlDocPtr) sxe->document->ptr)->encoding);
1426 			xmlOutputBufferFlush(outbuf);
1427 #ifdef LIBXML2_NEW_BUFFER
1428 			RETVAL_STRINGL((char *)xmlOutputBufferGetContent(outbuf), xmlOutputBufferGetSize(outbuf), 1);
1429 #else
1430 			RETVAL_STRINGL((char *)outbuf->buffer->content, outbuf->buffer->use, 1);
1431 #endif
1432 			xmlOutputBufferClose(outbuf);
1433 		}
1434 	} else {
1435 		RETVAL_FALSE;
1436 	}
1437 }
1438 /* }}} */
1439 
1440 #define SXE_NS_PREFIX(ns) (ns->prefix ? (char*)ns->prefix : "")
1441 
sxe_add_namespace_name(zval * return_value,xmlNsPtr ns)1442 static inline void sxe_add_namespace_name(zval *return_value, xmlNsPtr ns) /* {{{ */
1443 {
1444 	char *prefix = SXE_NS_PREFIX(ns);
1445 	if (zend_hash_exists(Z_ARRVAL_P(return_value), prefix, strlen(prefix) + 1) == 0) {
1446 		add_assoc_string(return_value, prefix, (char*)ns->href, 1);
1447 	}
1448 }
1449 /* }}} */
1450 
sxe_add_namespaces(php_sxe_object * sxe,xmlNodePtr node,zend_bool recursive,zval * return_value TSRMLS_DC)1451 static void sxe_add_namespaces(php_sxe_object *sxe, xmlNodePtr node, zend_bool recursive, zval *return_value TSRMLS_DC) /* {{{ */
1452 {
1453 	xmlAttrPtr  attr;
1454 
1455 	if (node->ns) {
1456 		sxe_add_namespace_name(return_value, node->ns);
1457 	}
1458 
1459 	attr = node->properties;
1460 	while (attr) {
1461 		if (attr->ns) {
1462 			sxe_add_namespace_name(return_value, attr->ns);
1463 		}
1464 		attr = attr->next;
1465 	}
1466 
1467 	if (recursive) {
1468 		node = node->children;
1469 		while (node) {
1470 			if (node->type == XML_ELEMENT_NODE) {
1471 				sxe_add_namespaces(sxe, node, recursive, return_value TSRMLS_CC);
1472 			}
1473 			node = node->next;
1474 		}
1475 	}
1476 } /* }}} */
1477 
1478 /* {{{ proto string SimpleXMLElement::getNamespaces([bool recursve])
1479    Return all namespaces in use */
SXE_METHOD(getNamespaces)1480 SXE_METHOD(getNamespaces)
1481 {
1482 	zend_bool           recursive = 0;
1483 	php_sxe_object     *sxe;
1484 	xmlNodePtr          node;
1485 
1486 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &recursive) == FAILURE) {
1487 		return;
1488 	}
1489 
1490 	array_init(return_value);
1491 
1492 	sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1493 	GET_NODE(sxe, node);
1494 	node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1495 
1496 	if (node) {
1497 		if (node->type == XML_ELEMENT_NODE) {
1498 			sxe_add_namespaces(sxe, node, recursive, return_value TSRMLS_CC);
1499 		} else if (node->type == XML_ATTRIBUTE_NODE && node->ns) {
1500 			sxe_add_namespace_name(return_value, node->ns);
1501 		}
1502 	}
1503 }
1504 /* }}} */
1505 
sxe_add_registered_namespaces(php_sxe_object * sxe,xmlNodePtr node,zend_bool recursive,zval * return_value TSRMLS_DC)1506 static void sxe_add_registered_namespaces(php_sxe_object *sxe, xmlNodePtr node, zend_bool recursive, zval *return_value TSRMLS_DC) /* {{{ */
1507 {
1508 	xmlNsPtr ns;
1509 
1510 	if (node->type == XML_ELEMENT_NODE) {
1511 		ns = node->nsDef;
1512 		while (ns != NULL) {
1513 			sxe_add_namespace_name(return_value, ns);
1514 			ns = ns->next;
1515 		}
1516 		if (recursive) {
1517 			node = node->children;
1518 			while (node) {
1519 				sxe_add_registered_namespaces(sxe, node, recursive, return_value TSRMLS_CC);
1520 				node = node->next;
1521 			}
1522 		}
1523 	}
1524 }
1525 /* }}} */
1526 
1527 /* {{{ proto string SimpleXMLElement::getDocNamespaces([bool recursive [, bool from_root])
1528    Return all namespaces registered with document */
SXE_METHOD(getDocNamespaces)1529 SXE_METHOD(getDocNamespaces)
1530 {
1531 	zend_bool           recursive = 0, from_root = 1;
1532 	php_sxe_object     *sxe;
1533 	xmlNodePtr          node;
1534 
1535 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|bb", &recursive, &from_root) == FAILURE) {
1536 		return;
1537 	}
1538 
1539 	sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1540 	if(from_root){
1541 		node = xmlDocGetRootElement((xmlDocPtr)sxe->document->ptr);
1542 	}else{
1543 		GET_NODE(sxe, node);
1544 	}
1545 
1546 	if (node == NULL) {
1547 		RETURN_FALSE;
1548 	}
1549 
1550 	array_init(return_value);
1551 	sxe_add_registered_namespaces(sxe, node, recursive, return_value TSRMLS_CC);
1552 }
1553 /* }}} */
1554 
1555 /* {{{ proto object SimpleXMLElement::children([string ns [, bool is_prefix]])
1556    Finds children of given node */
SXE_METHOD(children)1557 SXE_METHOD(children)
1558 {
1559 	php_sxe_object *sxe;
1560 	char           *nsprefix = NULL;
1561 	int             nsprefix_len = 0;
1562 	xmlNodePtr      node;
1563 	zend_bool       isprefix = 0;
1564 
1565 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!b", &nsprefix, &nsprefix_len, &isprefix) == FAILURE) {
1566 		return;
1567 	}
1568 
1569 	sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1570 
1571 	if (sxe->iter.type == SXE_ITER_ATTRLIST) {
1572 		return; /* attributes don't have attributes */
1573 	}
1574 
1575 	GET_NODE(sxe, node);
1576 	node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1577 
1578 	_node_as_zval(sxe, node, return_value, SXE_ITER_CHILD, NULL, (xmlChar *)nsprefix, isprefix TSRMLS_CC);
1579 
1580 }
1581 /* }}} */
1582 
1583 /* {{{ proto object SimpleXMLElement::getName()
1584    Finds children of given node */
SXE_METHOD(getName)1585 SXE_METHOD(getName)
1586 {
1587 	php_sxe_object *sxe;
1588 	xmlNodePtr      node;
1589 	int             namelen;
1590 
1591 	sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1592 
1593 	GET_NODE(sxe, node);
1594 	node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1595 	if (node) {
1596 		namelen = xmlStrlen(node->name);
1597 		RETURN_STRINGL((char*)node->name, namelen, 1);
1598 	} else {
1599 		RETURN_EMPTY_STRING();
1600 	}
1601 }
1602 /* }}} */
1603 
1604 /* {{{ proto array SimpleXMLElement::attributes([string ns [, bool is_prefix]])
1605    Identifies an element's attributes */
SXE_METHOD(attributes)1606 SXE_METHOD(attributes)
1607 {
1608 	php_sxe_object *sxe;
1609 	char           *nsprefix = NULL;
1610 	int             nsprefix_len = 0;
1611 	xmlNodePtr      node;
1612 	zend_bool       isprefix = 0;
1613 
1614 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!b", &nsprefix, &nsprefix_len, &isprefix) == FAILURE) {
1615 		return;
1616 	}
1617 
1618 	sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1619 	GET_NODE(sxe, node);
1620 
1621 	if (sxe->iter.type == SXE_ITER_ATTRLIST) {
1622 		return; /* attributes don't have attributes */
1623 	}
1624 
1625 	node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1626 
1627 	_node_as_zval(sxe, node, return_value, SXE_ITER_ATTRLIST, NULL, (xmlChar *)nsprefix, isprefix TSRMLS_CC);
1628 }
1629 /* }}} */
1630 
1631 /* {{{ proto void SimpleXMLElement::addChild(string qName [, string value [, string ns]])
1632    Add Element with optional namespace information */
SXE_METHOD(addChild)1633 SXE_METHOD(addChild)
1634 {
1635 	php_sxe_object *sxe;
1636 	char           *qname, *value = NULL, *nsuri = NULL;
1637 	int             qname_len, value_len = 0, nsuri_len = 0;
1638 	xmlNodePtr      node, newnode;
1639 	xmlNsPtr        nsptr = NULL;
1640 	xmlChar        *localname, *prefix = NULL;
1641 
1642 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!s!",
1643 		&qname, &qname_len, &value, &value_len, &nsuri, &nsuri_len) == FAILURE) {
1644 		return;
1645 	}
1646 
1647 	if (qname_len == 0) {
1648 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Element name is required");
1649 		return;
1650 	}
1651 
1652 	sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1653 	GET_NODE(sxe, node);
1654 
1655 	if (sxe->iter.type == SXE_ITER_ATTRLIST) {
1656 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element to attributes");
1657 		return;
1658 	}
1659 
1660 	node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1661 
1662 	if (node == NULL) {
1663 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add child. Parent is not a permanent member of the XML tree");
1664 		return;
1665 	}
1666 
1667 	localname = xmlSplitQName2((xmlChar *)qname, &prefix);
1668 	if (localname == NULL) {
1669 		localname = xmlStrdup((xmlChar *)qname);
1670 	}
1671 
1672 	newnode = xmlNewChild(node, NULL, localname, (xmlChar *)value);
1673 
1674 	if (nsuri != NULL) {
1675 		if (nsuri_len == 0) {
1676 			newnode->ns = NULL;
1677 			nsptr = xmlNewNs(newnode, (xmlChar *)nsuri, prefix);
1678 		} else {
1679 			nsptr = xmlSearchNsByHref(node->doc, node, (xmlChar *)nsuri);
1680 			if (nsptr == NULL) {
1681 				nsptr = xmlNewNs(newnode, (xmlChar *)nsuri, prefix);
1682 			}
1683 			newnode->ns = nsptr;
1684 		}
1685 	}
1686 
1687 	_node_as_zval(sxe, newnode, return_value, SXE_ITER_NONE, (char *)localname, prefix, 0 TSRMLS_CC);
1688 
1689 	xmlFree(localname);
1690 	if (prefix != NULL) {
1691 		xmlFree(prefix);
1692 	}
1693 }
1694 /* }}} */
1695 
1696 /* {{{ proto void SimpleXMLElement::addAttribute(string qName, string value [,string ns])
1697    Add Attribute with optional namespace information */
SXE_METHOD(addAttribute)1698 SXE_METHOD(addAttribute)
1699 {
1700 	php_sxe_object *sxe;
1701 	char           *qname, *value = NULL, *nsuri = NULL;
1702 	int             qname_len, value_len = 0, nsuri_len = 0;
1703 	xmlNodePtr      node;
1704 	xmlAttrPtr      attrp = NULL;
1705 	xmlNsPtr        nsptr = NULL;
1706 	xmlChar        *localname, *prefix = NULL;
1707 
1708 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s!",
1709 		&qname, &qname_len, &value, &value_len, &nsuri, &nsuri_len) == FAILURE) {
1710 		return;
1711 	}
1712 
1713 	if (qname_len == 0) {
1714 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attribute name is required");
1715 		return;
1716 	}
1717 
1718 	sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1719 	GET_NODE(sxe, node);
1720 
1721 	node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1722 
1723 	if (node && node->type != XML_ELEMENT_NODE) {
1724 		node = node->parent;
1725 	}
1726 
1727 	if (node == NULL) {
1728 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to locate parent Element");
1729 		return;
1730 	}
1731 
1732 	localname = xmlSplitQName2((xmlChar *)qname, &prefix);
1733 	if (localname == NULL) {
1734 		if (nsuri_len > 0) {
1735 			if (prefix != NULL) {
1736 				xmlFree(prefix);
1737 			}
1738 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attribute requires prefix for namespace");
1739 			return;
1740 		}
1741 		localname = xmlStrdup((xmlChar *)qname);
1742 	}
1743 
1744 	attrp = xmlHasNsProp(node, localname, (xmlChar *)nsuri);
1745 	if (attrp != NULL && attrp->type != XML_ATTRIBUTE_DECL) {
1746 		xmlFree(localname);
1747 		if (prefix != NULL) {
1748 			xmlFree(prefix);
1749 		}
1750 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attribute already exists");
1751 		return;
1752 	}
1753 
1754 	if (nsuri != NULL) {
1755 		nsptr = xmlSearchNsByHref(node->doc, node, (xmlChar *)nsuri);
1756 		if (nsptr == NULL) {
1757 			nsptr = xmlNewNs(node, (xmlChar *)nsuri, prefix);
1758 		}
1759 	}
1760 
1761 	attrp = xmlNewNsProp(node, nsptr, localname, (xmlChar *)value);
1762 
1763 	xmlFree(localname);
1764 	if (prefix != NULL) {
1765 		xmlFree(prefix);
1766 	}
1767 }
1768 /* }}} */
1769 
1770 /* {{{ cast_object()
1771  */
cast_object(zval * object,int type,char * contents TSRMLS_DC)1772 static int cast_object(zval *object, int type, char *contents TSRMLS_DC)
1773 {
1774 	if (contents) {
1775 		ZVAL_STRINGL(object, contents, strlen(contents), 1);
1776 	} else {
1777 		ZVAL_NULL(object);
1778 	}
1779 	Z_SET_REFCOUNT_P(object, 1);
1780 	Z_UNSET_ISREF_P(object);
1781 
1782 	switch (type) {
1783 		case IS_STRING:
1784 			convert_to_string(object);
1785 			break;
1786 		case IS_BOOL:
1787 			convert_to_boolean(object);
1788 			break;
1789 		case IS_LONG:
1790 			convert_to_long(object);
1791 			break;
1792 		case IS_DOUBLE:
1793 			convert_to_double(object);
1794 			break;
1795 		default:
1796 			return FAILURE;
1797 	}
1798 	return SUCCESS;
1799 }
1800 /* }}} */
1801 
1802 /* {{{ sxe_object_cast()
1803  */
sxe_object_cast(zval * readobj,zval * writeobj,int type TSRMLS_DC)1804 static int sxe_object_cast(zval *readobj, zval *writeobj, int type TSRMLS_DC)
1805 {
1806 	php_sxe_object *sxe;
1807 	xmlChar           *contents = NULL;
1808 	xmlNodePtr	    node;
1809 	int rv;
1810 	HashTable      *prop_hash;
1811 
1812 	sxe = php_sxe_fetch_object(readobj TSRMLS_CC);
1813 
1814 	if (type == IS_BOOL) {
1815 		node = php_sxe_get_first_node(sxe, NULL TSRMLS_CC);
1816 		prop_hash = sxe_get_prop_hash(readobj, 1 TSRMLS_CC);
1817 		INIT_PZVAL(writeobj);
1818 		ZVAL_BOOL(writeobj, node != NULL || zend_hash_num_elements(prop_hash) > 0);
1819 		zend_hash_destroy(prop_hash);
1820 		efree(prop_hash);
1821 		return SUCCESS;
1822 	}
1823 
1824 	if (sxe->iter.type != SXE_ITER_NONE) {
1825 		node = php_sxe_get_first_node(sxe, NULL TSRMLS_CC);
1826 		if (node) {
1827 			contents = xmlNodeListGetString((xmlDocPtr) sxe->document->ptr, node->children, 1);
1828 		}
1829 	} else {
1830 		if (!sxe->node) {
1831 			if (sxe->document) {
1832 				php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement((xmlDocPtr) sxe->document->ptr), NULL TSRMLS_CC);
1833 			}
1834 		}
1835 
1836 		if (sxe->node && sxe->node->node) {
1837 			if (sxe->node->node->children) {
1838 				contents = xmlNodeListGetString((xmlDocPtr) sxe->document->ptr, sxe->node->node->children, 1);
1839 			}
1840 		}
1841 	}
1842 
1843 	if (readobj == writeobj) {
1844 		INIT_PZVAL(writeobj);
1845 		zval_dtor(readobj);
1846 	}
1847 
1848 	rv = cast_object(writeobj, type, (char *)contents TSRMLS_CC);
1849 
1850 	if (contents) {
1851 		xmlFree(contents);
1852 	}
1853 	return rv;
1854 }
1855 /* }}} */
1856 
1857 /* {{{ proto object SimpleXMLElement::__toString() U
1858    Returns the string content */
SXE_METHOD(__toString)1859 SXE_METHOD(__toString)
1860 {
1861 	zval           *result;
1862 
1863 	ALLOC_INIT_ZVAL(result);
1864 
1865 	if (sxe_object_cast(getThis(), result, IS_STRING TSRMLS_CC) == SUCCESS) {
1866 		RETURN_ZVAL(result, 1, 1);
1867 	} else {
1868 		zval_ptr_dtor(&result);
1869 		RETURN_EMPTY_STRING();
1870 	}
1871 }
1872 /* }}} */
1873 
php_sxe_count_elements_helper(php_sxe_object * sxe,long * count TSRMLS_DC)1874 static int php_sxe_count_elements_helper(php_sxe_object *sxe, long *count TSRMLS_DC) /* {{{ */
1875 {
1876 	xmlNodePtr       node;
1877 	zval            *data;
1878 
1879 	*count = 0;
1880 
1881 	data = sxe->iter.data;
1882 	sxe->iter.data = NULL;
1883 
1884 	node = php_sxe_reset_iterator(sxe, 0 TSRMLS_CC);
1885 
1886 	while (node)
1887 	{
1888 		(*count)++;
1889 		node = php_sxe_iterator_fetch(sxe, node->next, 0 TSRMLS_CC);
1890 	}
1891 
1892 	if (sxe->iter.data) {
1893 		zval_ptr_dtor(&sxe->iter.data);
1894 	}
1895 	sxe->iter.data = data;
1896 
1897 	return SUCCESS;
1898 }
1899 /* }}} */
1900 
sxe_count_elements(zval * object,long * count TSRMLS_DC)1901 static int sxe_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */
1902 {
1903 	php_sxe_object  *intern;
1904 	intern = php_sxe_fetch_object(object TSRMLS_CC);
1905 	if (intern->fptr_count) {
1906 		zval *rv;
1907 		zend_call_method_with_0_params(&object, intern->zo.ce, &intern->fptr_count, "count", &rv);
1908 		if (rv) {
1909 			if (intern->tmp) {
1910 				zval_ptr_dtor(&intern->tmp);
1911 			}
1912 			MAKE_STD_ZVAL(intern->tmp);
1913 			ZVAL_ZVAL(intern->tmp, rv, 1, 1);
1914 			convert_to_long(intern->tmp);
1915 			*count = (long) Z_LVAL_P(intern->tmp);
1916 			return SUCCESS;
1917 		}
1918 		return FAILURE;
1919 	}
1920 	return php_sxe_count_elements_helper(intern, count TSRMLS_CC);
1921 }
1922 /* }}} */
1923 
1924 /* {{{ proto int SimpleXMLElement::count()
1925  Get number of child elements */
SXE_METHOD(count)1926 SXE_METHOD(count)
1927 {
1928 	long count = 0;
1929 	php_sxe_object *sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1930 
1931 	if (zend_parse_parameters_none() == FAILURE) {
1932 		return;
1933 	}
1934 
1935 	php_sxe_count_elements_helper(sxe, &count TSRMLS_CC);
1936 
1937 	RETURN_LONG(count);
1938 }
1939 /* }}} */
1940 
sxe_get_value(zval * z TSRMLS_DC)1941 static zval *sxe_get_value(zval *z TSRMLS_DC) /* {{{ */
1942 {
1943 	zval *retval;
1944 
1945 	MAKE_STD_ZVAL(retval);
1946 
1947 	if (sxe_object_cast(z, retval, IS_STRING TSRMLS_CC)==FAILURE) {
1948 		zend_error(E_ERROR, "Unable to cast node to string");
1949 		/* FIXME: Should not be fatal */
1950 	}
1951 
1952 	Z_SET_REFCOUNT_P(retval, 0);
1953 	return retval;
1954 }
1955 /* }}} */
1956 
1957 static zend_object_handlers sxe_object_handlers = { /* {{{ */
1958 	ZEND_OBJECTS_STORE_HANDLERS,
1959 	sxe_property_read,
1960 	sxe_property_write,
1961 	sxe_dimension_read,
1962 	sxe_dimension_write,
1963 	sxe_property_get_adr,
1964 	sxe_get_value,			/* get */
1965 	NULL,
1966 	sxe_property_exists,
1967 	sxe_property_delete,
1968 	sxe_dimension_exists,
1969 	sxe_dimension_delete,
1970 	sxe_get_properties,
1971 	NULL, /* zend_get_std_object_handlers()->get_method,*/
1972 	NULL, /* zend_get_std_object_handlers()->call_method,*/
1973 	NULL, /* zend_get_std_object_handlers()->get_constructor, */
1974 	NULL, /* zend_get_std_object_handlers()->get_class_entry,*/
1975 	NULL, /* zend_get_std_object_handlers()->get_class_name,*/
1976 	sxe_objects_compare,
1977 	sxe_object_cast,
1978 	sxe_count_elements,
1979 	sxe_get_debug_info,
1980 	NULL,
1981 	sxe_get_gc
1982 };
1983 /* }}} */
1984 
1985 /* {{{ sxe_object_clone()
1986  */
1987 static void
sxe_object_clone(void * object,void ** clone_ptr TSRMLS_DC)1988 sxe_object_clone(void *object, void **clone_ptr TSRMLS_DC)
1989 {
1990 	php_sxe_object *sxe = (php_sxe_object *) object;
1991 	php_sxe_object *clone;
1992 	xmlNodePtr nodep = NULL;
1993 	xmlDocPtr docp = NULL;
1994 
1995 	clone = php_sxe_object_new(sxe->zo.ce TSRMLS_CC);
1996 	clone->document = sxe->document;
1997 	if (clone->document) {
1998 		clone->document->refcount++;
1999 		docp = clone->document->ptr;
2000 	}
2001 
2002 	clone->iter.isprefix = sxe->iter.isprefix;
2003 	if (sxe->iter.name != NULL) {
2004 		clone->iter.name = xmlStrdup((xmlChar *)sxe->iter.name);
2005 	}
2006 	if (sxe->iter.nsprefix != NULL) {
2007 		clone->iter.nsprefix = xmlStrdup((xmlChar *)sxe->iter.nsprefix);
2008 	}
2009 	clone->iter.type = sxe->iter.type;
2010 
2011 	if (sxe->node) {
2012 		nodep = xmlDocCopyNode(sxe->node->node, docp, 1);
2013 	}
2014 
2015 	php_libxml_increment_node_ptr((php_libxml_node_object *)clone, nodep, NULL TSRMLS_CC);
2016 
2017 	*clone_ptr = (void *) clone;
2018 }
2019 /* }}} */
2020 
2021 /* {{{ sxe_object_dtor()
2022  */
sxe_object_dtor(void * object,zend_object_handle handle TSRMLS_DC)2023 static void sxe_object_dtor(void *object, zend_object_handle handle TSRMLS_DC)
2024 {
2025 	/* dtor required to cleanup iterator related data properly */
2026 
2027 	php_sxe_object *sxe;
2028 
2029 	sxe = (php_sxe_object *) object;
2030 
2031 	if (sxe->iter.data) {
2032 		zval_ptr_dtor(&sxe->iter.data);
2033 		sxe->iter.data = NULL;
2034 	}
2035 
2036 	if (sxe->iter.name) {
2037 		xmlFree(sxe->iter.name);
2038 		sxe->iter.name = NULL;
2039 	}
2040 	if (sxe->iter.nsprefix) {
2041 		xmlFree(sxe->iter.nsprefix);
2042 		sxe->iter.nsprefix = NULL;
2043 	}
2044 	if (sxe->tmp) {
2045 		zval_ptr_dtor(&sxe->tmp);
2046 		sxe->tmp = NULL;
2047 	}
2048 }
2049 /* }}} */
2050 
2051 /* {{{ sxe_object_free_storage()
2052  */
sxe_object_free_storage(void * object TSRMLS_DC)2053 static void sxe_object_free_storage(void *object TSRMLS_DC)
2054 {
2055 	php_sxe_object *sxe;
2056 
2057 	sxe = (php_sxe_object *) object;
2058 
2059 #if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION == 1 && PHP_RELEASE_VERSION > 2) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 1) || (PHP_MAJOR_VERSION > 5)
2060 	zend_object_std_dtor(&sxe->zo TSRMLS_CC);
2061 #else
2062 	if (sxe->zo.guards) {
2063 		zend_hash_destroy(sxe->zo.guards);
2064 		FREE_HASHTABLE(sxe->zo.guards);
2065 	}
2066 
2067 	if (sxe->zo.properties) {
2068 		zend_hash_destroy(sxe->zo.properties);
2069 		FREE_HASHTABLE(sxe->zo.properties);
2070 	}
2071 #endif
2072 
2073 	php_libxml_node_decrement_resource((php_libxml_node_object *)sxe TSRMLS_CC);
2074 
2075 	if (sxe->xpath) {
2076 		xmlXPathFreeContext(sxe->xpath);
2077 	}
2078 
2079 	if (sxe->properties) {
2080 		zend_hash_destroy(sxe->properties);
2081 		FREE_HASHTABLE(sxe->properties);
2082 	}
2083 
2084 	efree(object);
2085 }
2086 /* }}} */
2087 
2088 /* {{{ php_sxe_object_new()
2089  */
php_sxe_object_new(zend_class_entry * ce TSRMLS_DC)2090 static php_sxe_object* php_sxe_object_new(zend_class_entry *ce TSRMLS_DC)
2091 {
2092 	php_sxe_object *intern;
2093 	zend_class_entry     *parent = ce;
2094 	int inherited = 0;
2095 
2096 	intern = ecalloc(1, sizeof(php_sxe_object));
2097 
2098 	intern->iter.type = SXE_ITER_NONE;
2099 	intern->iter.nsprefix = NULL;
2100 	intern->iter.name = NULL;
2101 	intern->fptr_count = NULL;
2102 
2103 #if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION == 1 && PHP_RELEASE_VERSION > 2) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 1) || (PHP_MAJOR_VERSION > 5)
2104 	zend_object_std_init(&intern->zo, ce TSRMLS_CC);
2105 #else
2106 	ALLOC_HASHTABLE(intern->zo.properties);
2107 	zend_hash_init(intern->zo.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
2108 
2109 	intern->zo.ce = ce;
2110 	intern->zo.guards = NULL;
2111 #endif
2112 
2113 	while (parent) {
2114 		if (parent == sxe_class_entry) {
2115 			break;
2116 		}
2117 
2118 		parent = parent->parent;
2119 		inherited = 1;
2120 	}
2121 
2122 	if (inherited) {
2123 		zend_hash_find(&ce->function_table, "count", sizeof("count"),(void **) &intern->fptr_count);
2124 		if (intern->fptr_count->common.scope == parent) {
2125 			intern->fptr_count = NULL;
2126 		}
2127 	}
2128 
2129 	return intern;
2130 }
2131 /* }}} */
2132 
2133 /* {{{ php_sxe_register_object
2134  */
2135 static zend_object_value
php_sxe_register_object(php_sxe_object * intern TSRMLS_DC)2136 php_sxe_register_object(php_sxe_object *intern TSRMLS_DC)
2137 {
2138 	zend_object_value rv;
2139 
2140 	rv.handle = zend_objects_store_put(intern, sxe_object_dtor, (zend_objects_free_object_storage_t)sxe_object_free_storage, sxe_object_clone TSRMLS_CC);
2141 	rv.handlers = (zend_object_handlers *) &sxe_object_handlers;
2142 
2143 	return rv;
2144 }
2145 /* }}} */
2146 
2147 /* {{{ sxe_object_new()
2148  */
2149 PHP_SXE_API zend_object_value
sxe_object_new(zend_class_entry * ce TSRMLS_DC)2150 sxe_object_new(zend_class_entry *ce TSRMLS_DC)
2151 {
2152 	php_sxe_object    *intern;
2153 
2154 	intern = php_sxe_object_new(ce TSRMLS_CC);
2155 	return php_sxe_register_object(intern TSRMLS_CC);
2156 }
2157 /* }}} */
2158 
2159 /* {{{ proto simplemxml_element simplexml_load_file(string filename [, string class_name [, int options [, string ns [, bool is_prefix]]]])
2160    Load a filename and return a simplexml_element object to allow for processing */
PHP_FUNCTION(simplexml_load_file)2161 PHP_FUNCTION(simplexml_load_file)
2162 {
2163 	php_sxe_object *sxe;
2164 	char           *filename;
2165 	int             filename_len;
2166 	xmlDocPtr       docp;
2167 	char           *ns = NULL;
2168 	int             ns_len = 0;
2169 	long            options = 0;
2170 	zend_class_entry *ce= sxe_class_entry;
2171 	zend_bool       isprefix = 0;
2172 
2173 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p|C!lsb", &filename, &filename_len, &ce, &options, &ns, &ns_len, &isprefix) == FAILURE) {
2174 		return;
2175 	}
2176 
2177 	docp = xmlReadFile(filename, NULL, options);
2178 
2179 	if (! docp) {
2180 		RETURN_FALSE;
2181 	}
2182 
2183 	if (!ce) {
2184 		ce = sxe_class_entry;
2185 	}
2186 	sxe = php_sxe_object_new(ce TSRMLS_CC);
2187 	sxe->iter.nsprefix = ns_len ? xmlStrdup((xmlChar *)ns) : NULL;
2188 	sxe->iter.isprefix = isprefix;
2189 	php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp TSRMLS_CC);
2190 	php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL TSRMLS_CC);
2191 
2192 	return_value->type = IS_OBJECT;
2193 	return_value->value.obj = php_sxe_register_object(sxe TSRMLS_CC);
2194 }
2195 /* }}} */
2196 
2197 /* {{{ proto simplemxml_element simplexml_load_string(string data [, string class_name [, int options [, string ns [, bool is_prefix]]]])
2198    Load a string and return a simplexml_element object to allow for processing */
PHP_FUNCTION(simplexml_load_string)2199 PHP_FUNCTION(simplexml_load_string)
2200 {
2201 	php_sxe_object *sxe;
2202 	char           *data;
2203 	int             data_len;
2204 	xmlDocPtr       docp;
2205 	char           *ns = NULL;
2206 	int             ns_len = 0;
2207 	long            options = 0;
2208 	zend_class_entry *ce= sxe_class_entry;
2209 	zend_bool       isprefix = 0;
2210 
2211 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|C!lsb", &data, &data_len, &ce, &options, &ns, &ns_len, &isprefix) == FAILURE) {
2212 		return;
2213 	}
2214 
2215 	docp = xmlReadMemory(data, data_len, NULL, NULL, options);
2216 
2217 	if (! docp) {
2218 		RETURN_FALSE;
2219 	}
2220 
2221 	if (!ce) {
2222 		ce = sxe_class_entry;
2223 	}
2224 	sxe = php_sxe_object_new(ce TSRMLS_CC);
2225 	sxe->iter.nsprefix = ns_len ? xmlStrdup((xmlChar *)ns) : NULL;
2226 	sxe->iter.isprefix = isprefix;
2227 	php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp TSRMLS_CC);
2228 	php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL TSRMLS_CC);
2229 
2230 	return_value->type = IS_OBJECT;
2231 	return_value->value.obj = php_sxe_register_object(sxe TSRMLS_CC);
2232 }
2233 /* }}} */
2234 
2235 /* {{{ proto SimpleXMLElement::__construct(string data [, int options [, bool data_is_url [, string ns [, bool is_prefix]]]])
2236    SimpleXMLElement constructor */
SXE_METHOD(__construct)2237 SXE_METHOD(__construct)
2238 {
2239 	php_sxe_object *sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
2240 	char           *data, *ns = NULL;
2241 	int             data_len, ns_len = 0;
2242 	xmlDocPtr       docp;
2243 	long            options = 0;
2244 	zend_bool       is_url = 0, isprefix = 0;
2245 	zend_error_handling error_handling;
2246 
2247 	zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
2248 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lbsb", &data, &data_len, &options, &is_url, &ns, &ns_len, &isprefix) == FAILURE) {
2249 		zend_restore_error_handling(&error_handling TSRMLS_CC);
2250 		return;
2251 	}
2252 
2253 	zend_restore_error_handling(&error_handling TSRMLS_CC);
2254 
2255 	docp = is_url ? xmlReadFile(data, NULL, options) : xmlReadMemory(data, data_len, NULL, NULL, options);
2256 
2257 	if (!docp) {
2258 		((php_libxml_node_object *)sxe)->document = NULL;
2259 		zend_throw_exception(zend_exception_get_default(TSRMLS_C), "String could not be parsed as XML", 0 TSRMLS_CC);
2260 		return;
2261 	}
2262 
2263 	sxe->iter.nsprefix = ns_len ? xmlStrdup((xmlChar *)ns) : NULL;
2264 	sxe->iter.isprefix = isprefix;
2265 	php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp TSRMLS_CC);
2266 	php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL TSRMLS_CC);
2267 }
2268 /* }}} */
2269 
2270 zend_object_iterator_funcs php_sxe_iterator_funcs = { /* {{{ */
2271 	php_sxe_iterator_dtor,
2272 	php_sxe_iterator_valid,
2273 	php_sxe_iterator_current_data,
2274 	php_sxe_iterator_current_key,
2275 	php_sxe_iterator_move_forward,
2276 	php_sxe_iterator_rewind,
2277 };
2278 /* }}} */
2279 
php_sxe_iterator_fetch(php_sxe_object * sxe,xmlNodePtr node,int use_data TSRMLS_DC)2280 static xmlNodePtr php_sxe_iterator_fetch(php_sxe_object *sxe, xmlNodePtr node, int use_data TSRMLS_DC) /* {{{ */
2281 {
2282 	xmlChar *prefix  = sxe->iter.nsprefix;
2283 	int isprefix  = sxe->iter.isprefix;
2284 	int test_elem = sxe->iter.type == SXE_ITER_ELEMENT  && sxe->iter.name;
2285 	int test_attr = sxe->iter.type == SXE_ITER_ATTRLIST && sxe->iter.name;
2286 
2287 	while (node) {
2288 		SKIP_TEXT(node);
2289 		if (sxe->iter.type != SXE_ITER_ATTRLIST && node->type == XML_ELEMENT_NODE) {
2290 			if ((!test_elem || !xmlStrcmp(node->name, sxe->iter.name)) && match_ns(sxe, node, prefix, isprefix)) {
2291 				break;
2292 			}
2293 		} else if (node->type == XML_ATTRIBUTE_NODE) {
2294 			if ((!test_attr || !xmlStrcmp(node->name, sxe->iter.name)) && match_ns(sxe, node, prefix, isprefix)) {
2295 				break;
2296 			}
2297 		}
2298 next_iter:
2299 		node = node->next;
2300 	}
2301 
2302 	if (node && use_data) {
2303 		ALLOC_INIT_ZVAL(sxe->iter.data);
2304 		_node_as_zval(sxe, node, sxe->iter.data, SXE_ITER_NONE, NULL, prefix, isprefix TSRMLS_CC);
2305 	}
2306 
2307 	return node;
2308 }
2309 /* }}} */
2310 
php_sxe_reset_iterator(php_sxe_object * sxe,int use_data TSRMLS_DC)2311 static xmlNodePtr php_sxe_reset_iterator(php_sxe_object *sxe, int use_data TSRMLS_DC) /* {{{ */
2312 {
2313 	xmlNodePtr node;
2314 
2315 	if (sxe->iter.data) {
2316 		zval_ptr_dtor(&sxe->iter.data);
2317 		sxe->iter.data = NULL;
2318 	}
2319 
2320 	GET_NODE(sxe, node)
2321 
2322 	if (node) {
2323 		switch (sxe->iter.type) {
2324 			case SXE_ITER_ELEMENT:
2325 			case SXE_ITER_CHILD:
2326 			case SXE_ITER_NONE:
2327 				node = node->children;
2328 				break;
2329 			case SXE_ITER_ATTRLIST:
2330 				node = (xmlNodePtr) node->properties;
2331 		}
2332 		return php_sxe_iterator_fetch(sxe, node, use_data TSRMLS_CC);
2333 	}
2334 	return NULL;
2335 }
2336 /* }}} */
2337 
php_sxe_get_iterator(zend_class_entry * ce,zval * object,int by_ref TSRMLS_DC)2338 zend_object_iterator *php_sxe_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
2339 {
2340 	php_sxe_iterator *iterator;
2341 
2342 	if (by_ref) {
2343 		zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
2344 	}
2345 	iterator = emalloc(sizeof(php_sxe_iterator));
2346 
2347 	Z_ADDREF_P(object);
2348 	iterator->intern.data = (void*)object;
2349 	iterator->intern.funcs = &php_sxe_iterator_funcs;
2350 	iterator->sxe = php_sxe_fetch_object(object TSRMLS_CC);
2351 
2352 	return (zend_object_iterator*)iterator;
2353 }
2354 /* }}} */
2355 
php_sxe_iterator_dtor(zend_object_iterator * iter TSRMLS_DC)2356 static void php_sxe_iterator_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
2357 {
2358 	php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2359 
2360 	/* cleanup handled in sxe_object_dtor as we dont always have an iterator wrapper */
2361 	if (iterator->intern.data) {
2362 		zval_ptr_dtor((zval**)&iterator->intern.data);
2363 	}
2364 
2365 	efree(iterator);
2366 }
2367 /* }}} */
2368 
php_sxe_iterator_valid(zend_object_iterator * iter TSRMLS_DC)2369 static int php_sxe_iterator_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
2370 {
2371 	php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2372 
2373 	return iterator->sxe->iter.data ? SUCCESS : FAILURE;
2374 }
2375 /* }}} */
2376 
php_sxe_iterator_current_data(zend_object_iterator * iter,zval *** data TSRMLS_DC)2377 static void php_sxe_iterator_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */
2378 {
2379 	php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2380 
2381 	*data = &iterator->sxe->iter.data;
2382 }
2383 /* }}} */
2384 
php_sxe_iterator_current_key(zend_object_iterator * iter,char ** str_key,uint * str_key_len,ulong * int_key TSRMLS_DC)2385 static int php_sxe_iterator_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
2386 {
2387 	zval *curobj;
2388 	xmlNodePtr curnode = NULL;
2389 	php_sxe_object *intern;
2390 	int namelen;
2391 
2392 	php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2393 	curobj = iterator->sxe->iter.data;
2394 
2395 	intern = (php_sxe_object *)zend_object_store_get_object(curobj TSRMLS_CC);
2396 	if (intern != NULL && intern->node != NULL) {
2397 		curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->node)->node;
2398 	}
2399 	if (!curnode) {
2400 		return HASH_KEY_NON_EXISTANT;
2401 	}
2402 
2403 	namelen = xmlStrlen(curnode->name);
2404 	*str_key = estrndup((char *)curnode->name, namelen);
2405 	*str_key_len = namelen + 1;
2406 	return HASH_KEY_IS_STRING;
2407 
2408 }
2409 /* }}} */
2410 
php_sxe_move_forward_iterator(php_sxe_object * sxe TSRMLS_DC)2411 PHP_SXE_API void php_sxe_move_forward_iterator(php_sxe_object *sxe TSRMLS_DC) /* {{{ */
2412 {
2413 	xmlNodePtr      node = NULL;
2414 	php_sxe_object  *intern;
2415 
2416 	if (sxe->iter.data) {
2417 		intern = (php_sxe_object *)zend_object_store_get_object(sxe->iter.data TSRMLS_CC);
2418 		GET_NODE(intern, node)
2419 		zval_ptr_dtor(&sxe->iter.data);
2420 		sxe->iter.data = NULL;
2421 	}
2422 
2423 	if (node) {
2424 		php_sxe_iterator_fetch(sxe, node->next, 1 TSRMLS_CC);
2425 	}
2426 }
2427 /* }}} */
2428 
php_sxe_iterator_move_forward(zend_object_iterator * iter TSRMLS_DC)2429 static void php_sxe_iterator_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
2430 {
2431 	php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2432 	php_sxe_move_forward_iterator(iterator->sxe TSRMLS_CC);
2433 }
2434 /* }}} */
2435 
php_sxe_iterator_rewind(zend_object_iterator * iter TSRMLS_DC)2436 static void php_sxe_iterator_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
2437 {
2438 	php_sxe_object	*sxe;
2439 
2440 	php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2441 	sxe = iterator->sxe;
2442 
2443 	php_sxe_reset_iterator(sxe, 1 TSRMLS_CC);
2444 }
2445 /* }}} */
2446 
simplexml_export_node(zval * object TSRMLS_DC)2447 void *simplexml_export_node(zval *object TSRMLS_DC) /* {{{ */
2448 {
2449 	php_sxe_object *sxe;
2450 	xmlNodePtr node;
2451 
2452 	sxe = php_sxe_fetch_object(object TSRMLS_CC);
2453 	GET_NODE(sxe, node);
2454 	return php_sxe_get_first_node(sxe, node TSRMLS_CC);
2455 }
2456 /* }}} */
2457 
2458 /* {{{ proto simplemxml_element simplexml_import_dom(domNode node [, string class_name])
2459    Get a simplexml_element object from dom to allow for processing */
PHP_FUNCTION(simplexml_import_dom)2460 PHP_FUNCTION(simplexml_import_dom)
2461 {
2462 	php_sxe_object *sxe;
2463 	zval *node;
2464 	php_libxml_node_object *object;
2465 	xmlNodePtr		nodep = NULL;
2466 	zend_class_entry *ce= sxe_class_entry;
2467 
2468 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o|C!", &node, &ce) == FAILURE) {
2469 		return;
2470 	}
2471 
2472 	object = (php_libxml_node_object *)zend_object_store_get_object(node TSRMLS_CC);
2473 
2474 	nodep = php_libxml_import_node(node TSRMLS_CC);
2475 
2476 	if (nodep) {
2477 		if (nodep->doc == NULL) {
2478 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Imported Node must have associated Document");
2479 			RETURN_NULL();
2480 		}
2481 		if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
2482 			nodep = xmlDocGetRootElement((xmlDocPtr) nodep);
2483 		}
2484 	}
2485 
2486 	if (nodep && nodep->type == XML_ELEMENT_NODE) {
2487 		if (!ce) {
2488 			ce = sxe_class_entry;
2489 		}
2490 		sxe = php_sxe_object_new(ce TSRMLS_CC);
2491 		sxe->document = object->document;
2492 		php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, nodep->doc TSRMLS_CC);
2493 		php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, nodep, NULL TSRMLS_CC);
2494 
2495 		return_value->type = IS_OBJECT;
2496 		return_value->value.obj = php_sxe_register_object(sxe TSRMLS_CC);
2497 	} else {
2498 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Nodetype to import");
2499 		RETVAL_NULL();
2500 	}
2501 }
2502 /* }}} */
2503 
2504 /* {{{ arginfo */
2505 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexml_load_file, 0, 0, 1)
2506 	ZEND_ARG_INFO(0, filename)
2507 	ZEND_ARG_INFO(0, class_name)
2508 	ZEND_ARG_INFO(0, options)
2509 	ZEND_ARG_INFO(0, ns)
2510 	ZEND_ARG_INFO(0, is_prefix)
2511 ZEND_END_ARG_INFO()
2512 
2513 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexml_load_string, 0, 0, 1)
2514 	ZEND_ARG_INFO(0, data)
2515 	ZEND_ARG_INFO(0, class_name)
2516 	ZEND_ARG_INFO(0, options)
2517 	ZEND_ARG_INFO(0, ns)
2518 	ZEND_ARG_INFO(0, is_prefix)
2519 ZEND_END_ARG_INFO()
2520 
2521 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexml_import_dom, 0, 0, 1)
2522 	ZEND_ARG_INFO(0, node)
2523 	ZEND_ARG_INFO(0, class_name)
2524 ZEND_END_ARG_INFO()
2525 
2526 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_xpath, 0, 0, 1)
2527 	ZEND_ARG_INFO(0, path)
2528 ZEND_END_ARG_INFO()
2529 
2530 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_registerxpathnamespace, 0, 0, 2)
2531 	ZEND_ARG_INFO(0, prefix)
2532 	ZEND_ARG_INFO(0, ns)
2533 ZEND_END_ARG_INFO()
2534 
2535 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_asxml, 0, 0, 0)
2536 	ZEND_ARG_INFO(0, filename)
2537 ZEND_END_ARG_INFO()
2538 
2539 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_getnamespaces, 0, 0, 0)
2540 	ZEND_ARG_INFO(0, recursve)
2541 ZEND_END_ARG_INFO()
2542 
2543 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_getdocnamespaces, 0, 0, 0)
2544 	ZEND_ARG_INFO(0, recursve)
2545 	ZEND_ARG_INFO(0, from_root)
2546 ZEND_END_ARG_INFO()
2547 
2548 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_children, 0, 0, 0)
2549 	ZEND_ARG_INFO(0, ns)
2550 	ZEND_ARG_INFO(0, is_prefix)
2551 ZEND_END_ARG_INFO()
2552 
2553 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement__construct, 0, 0, 1)
2554 	ZEND_ARG_INFO(0, data)
2555 	ZEND_ARG_INFO(0, options)
2556 	ZEND_ARG_INFO(0, data_is_url)
2557 	ZEND_ARG_INFO(0, ns)
2558 	ZEND_ARG_INFO(0, is_prefix)
2559 ZEND_END_ARG_INFO()
2560 
2561 ZEND_BEGIN_ARG_INFO(arginfo_simplexmlelement__void, 0)
2562 ZEND_END_ARG_INFO()
2563 
2564 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_addchild, 0, 0, 1)
2565 	ZEND_ARG_INFO(0, name)
2566 	ZEND_ARG_INFO(0, value)
2567 	ZEND_ARG_INFO(0, ns)
2568 ZEND_END_ARG_INFO()
2569 /* }}} */
2570 
2571 const zend_function_entry simplexml_functions[] = { /* {{{ */
2572 	PHP_FE(simplexml_load_file, 	arginfo_simplexml_load_file)
2573 	PHP_FE(simplexml_load_string,	arginfo_simplexml_load_string)
2574 	PHP_FE(simplexml_import_dom,	arginfo_simplexml_import_dom)
2575 	PHP_FE_END
2576 };
2577 /* }}} */
2578 
2579 static const zend_module_dep simplexml_deps[] = { /* {{{ */
2580 	ZEND_MOD_REQUIRED("libxml")
2581 	ZEND_MOD_REQUIRED("spl")
2582 	ZEND_MOD_END
2583 };
2584 /* }}} */
2585 
2586 zend_module_entry simplexml_module_entry = { /* {{{ */
2587 	STANDARD_MODULE_HEADER_EX, NULL,
2588 	simplexml_deps,
2589 	"SimpleXML",
2590 	simplexml_functions,
2591 	PHP_MINIT(simplexml),
2592 	PHP_MSHUTDOWN(simplexml),
2593 	NULL,
2594 	NULL,
2595 	PHP_MINFO(simplexml),
2596 	"0.1",
2597 	STANDARD_MODULE_PROPERTIES
2598 };
2599 /* }}} */
2600 
2601 #ifdef COMPILE_DL_SIMPLEXML
2602 ZEND_GET_MODULE(simplexml)
2603 #endif
2604 
2605 /* the method table */
2606 /* each method can have its own parameters and visibility */
2607 static const zend_function_entry sxe_functions[] = { /* {{{ */
2608 	SXE_ME(__construct,            arginfo_simplexmlelement__construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) /* must be called */
2609 	SXE_ME(asXML,                  arginfo_simplexmlelement_asxml, ZEND_ACC_PUBLIC)
2610 	SXE_MALIAS(saveXML, asXML,	   arginfo_simplexmlelement_asxml, ZEND_ACC_PUBLIC)
2611 	SXE_ME(xpath,                  arginfo_simplexmlelement_xpath, ZEND_ACC_PUBLIC)
2612 	SXE_ME(registerXPathNamespace, arginfo_simplexmlelement_registerxpathnamespace, ZEND_ACC_PUBLIC)
2613 	SXE_ME(attributes,             arginfo_simplexmlelement_children, ZEND_ACC_PUBLIC)
2614 	SXE_ME(children,               arginfo_simplexmlelement_children, ZEND_ACC_PUBLIC)
2615 	SXE_ME(getNamespaces,          arginfo_simplexmlelement_getnamespaces, ZEND_ACC_PUBLIC)
2616 	SXE_ME(getDocNamespaces,       arginfo_simplexmlelement_getdocnamespaces, ZEND_ACC_PUBLIC)
2617 	SXE_ME(getName,                arginfo_simplexmlelement__void, ZEND_ACC_PUBLIC)
2618 	SXE_ME(addChild,               arginfo_simplexmlelement_addchild, ZEND_ACC_PUBLIC)
2619 	SXE_ME(addAttribute,           arginfo_simplexmlelement_addchild, ZEND_ACC_PUBLIC)
2620 	SXE_ME(__toString,             arginfo_simplexmlelement__void, ZEND_ACC_PUBLIC)
2621 	SXE_ME(count,                  arginfo_simplexmlelement__void, ZEND_ACC_PUBLIC)
2622 	PHP_FE_END
2623 };
2624 /* }}} */
2625 
2626 /* {{{ PHP_MINIT_FUNCTION(simplexml)
2627  */
PHP_MINIT_FUNCTION(simplexml)2628 PHP_MINIT_FUNCTION(simplexml)
2629 {
2630 	zend_class_entry sxe;
2631 
2632 	INIT_CLASS_ENTRY(sxe, "SimpleXMLElement", sxe_functions);
2633 	sxe.create_object = sxe_object_new;
2634 	sxe_class_entry = zend_register_internal_class(&sxe TSRMLS_CC);
2635 	sxe_class_entry->get_iterator = php_sxe_get_iterator;
2636 	sxe_class_entry->iterator_funcs.funcs = &php_sxe_iterator_funcs;
2637 	zend_class_implements(sxe_class_entry TSRMLS_CC, 1, zend_ce_traversable);
2638 	sxe_object_handlers.get_method = zend_get_std_object_handlers()->get_method;
2639 	sxe_object_handlers.get_constructor = zend_get_std_object_handlers()->get_constructor;
2640 	sxe_object_handlers.get_class_entry = zend_get_std_object_handlers()->get_class_entry;
2641 	sxe_object_handlers.get_class_name = zend_get_std_object_handlers()->get_class_name;
2642 	sxe_class_entry->serialize = zend_class_serialize_deny;
2643 	sxe_class_entry->unserialize = zend_class_unserialize_deny;
2644 
2645 	php_libxml_register_export(sxe_class_entry, simplexml_export_node);
2646 
2647 	PHP_MINIT(sxe)(INIT_FUNC_ARGS_PASSTHRU);
2648 
2649 	return SUCCESS;
2650 }
2651 /* }}} */
2652 
2653 /* {{{ PHP_MSHUTDOWN_FUNCTION(simplexml)
2654  */
PHP_MSHUTDOWN_FUNCTION(simplexml)2655 PHP_MSHUTDOWN_FUNCTION(simplexml)
2656 {
2657 	sxe_class_entry = NULL;
2658 	return SUCCESS;
2659 }
2660 /* }}} */
2661 
2662 /* {{{ PHP_MINFO_FUNCTION(simplexml)
2663  */
PHP_MINFO_FUNCTION(simplexml)2664 PHP_MINFO_FUNCTION(simplexml)
2665 {
2666 	php_info_print_table_start();
2667 	php_info_print_table_header(2, "Simplexml support", "enabled");
2668 	php_info_print_table_row(2, "Revision", "$Id: 16070fc92ad6f69cebb2d52ad3f02794f833ce39 $");
2669 	php_info_print_table_row(2, "Schema support",
2670 #ifdef LIBXML_SCHEMAS_ENABLED
2671 		"enabled");
2672 #else
2673 		"not available");
2674 #endif
2675 	php_info_print_table_end();
2676 }
2677 /* }}} */
2678 
2679 #endif
2680 
2681 /**
2682  * Local Variables:
2683  * c-basic-offset: 4
2684  * tab-width: 4
2685  * indent-tabs-mode: t
2686  * End:
2687  * vim600: fdm=marker
2688  * vim: noet sw=4 ts=4
2689  */
2690