xref: /PHP-5.3/ext/simplexml/simplexml.c (revision a2045ff3)
1 /*
2   +----------------------------------------------------------------------+
3   | PHP Version 5                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2013 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: 02ab7893b36d51e9c59da77d7e287eb3b35e1e32 $ */
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 TSRMLS_DC)392 static zval * sxe_property_read(zval *object, zval *member, int type 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 TSRMLS_DC)683 static void sxe_property_write(zval *object, zval *member, zval *value 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 TSRMLS_DC)697 static zval** sxe_property_get_adr(zval *object, zval *member 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 TSRMLS_DC)849 static int sxe_property_exists(zval *object, zval *member, int check_empty 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 TSRMLS_DC)974 static void sxe_property_delete(zval *object, zval *member 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 
1073 	sxe = php_sxe_fetch_object(object TSRMLS_CC);
1074 
1075 	if (is_debug) {
1076 		ALLOC_HASHTABLE(rv);
1077 		zend_hash_init(rv, 0, NULL, ZVAL_PTR_DTOR, 0);
1078 	}
1079 	else if (sxe->properties) {
1080 		if (GC_G(gc_active)) {
1081 			return sxe->properties;
1082 		}
1083 		zend_hash_clean(sxe->properties);
1084 		rv = sxe->properties;
1085 	} else {
1086 		if (GC_G(gc_active)) {
1087 			return NULL;
1088 		}
1089 		ALLOC_HASHTABLE(rv);
1090 		zend_hash_init(rv, 0, NULL, ZVAL_PTR_DTOR, 0);
1091 		sxe->properties = rv;
1092 	}
1093 
1094 	GET_NODE(sxe, node);
1095 	if (!node) {
1096 		return rv;
1097 	}
1098 	if (is_debug || sxe->iter.type != SXE_ITER_CHILD) {
1099 		if (sxe->iter.type == SXE_ITER_ELEMENT) {
1100 			node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1101 		}
1102 		if (!node || node->type != XML_ENTITY_DECL) {
1103 			attr = node ? (xmlAttrPtr)node->properties : NULL;
1104 			zattr = NULL;
1105 			test = sxe->iter.name && sxe->iter.type == SXE_ITER_ATTRLIST;
1106 			while (attr) {
1107 				if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr)attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
1108 					MAKE_STD_ZVAL(value);
1109 					ZVAL_STRING(value, sxe_xmlNodeListGetString((xmlDocPtr) sxe->document->ptr, attr->children, 1), 0);
1110 					namelen = xmlStrlen(attr->name) + 1;
1111 					if (!zattr) {
1112 						MAKE_STD_ZVAL(zattr);
1113 						array_init(zattr);
1114 						sxe_properties_add(rv, "@attributes", sizeof("@attributes"), zattr TSRMLS_CC);
1115 					}
1116 					add_assoc_zval_ex(zattr, (char*)attr->name, namelen, value);
1117 				}
1118 				attr = attr->next;
1119 			}
1120 		}
1121 	}
1122 
1123 	GET_NODE(sxe, node);
1124 	node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1125 	if (node && sxe->iter.type != SXE_ITER_ATTRLIST) {
1126 		if (node->type == XML_ATTRIBUTE_NODE) {
1127 			MAKE_STD_ZVAL(value);
1128 			ZVAL_STRING(value, sxe_xmlNodeListGetString(node->doc, node->children, 1), 0);
1129 			zend_hash_next_index_insert(rv, &value, sizeof(zval *), NULL);
1130 			node = NULL;
1131 		} else if (sxe->iter.type != SXE_ITER_CHILD) {
1132 			node = node->children;
1133 		}
1134 
1135 		while (node) {
1136 			if (node->children != NULL || node->prev != NULL || node->next != NULL) {
1137 				SKIP_TEXT(node);
1138 			} else {
1139 				if (node->type == XML_TEXT_NODE) {
1140 					const xmlChar *cur = node->content;
1141 
1142 					if (*cur != 0) {
1143 						MAKE_STD_ZVAL(value);
1144 						ZVAL_STRING(value, sxe_xmlNodeListGetString(node->doc, node, 1), 0);
1145 						zend_hash_next_index_insert(rv, &value, sizeof(zval *), NULL);
1146 					}
1147 					goto next_iter;
1148 				}
1149 			}
1150 
1151 			if (node->type == XML_ELEMENT_NODE && (! match_ns(sxe, node, sxe->iter.nsprefix, sxe->iter.isprefix))) {
1152 				goto next_iter;
1153 			}
1154 
1155 			name = (char *) node->name;
1156 			if (!name) {
1157 				goto next_iter;
1158 			} else {
1159 				namelen = xmlStrlen(node->name) + 1;
1160 			}
1161 
1162 			_get_base_node_value(sxe, node, &value, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC);
1163 
1164 			sxe_properties_add(rv, name, namelen, value TSRMLS_CC);
1165 next_iter:
1166 			node = node->next;
1167 		}
1168 	}
1169 
1170 	return rv;
1171 }
1172 /* }}} */
1173 
sxe_get_properties(zval * object TSRMLS_DC)1174 static HashTable * sxe_get_properties(zval *object TSRMLS_DC) /* {{{ */
1175 {
1176 	return sxe_get_prop_hash(object, 0 TSRMLS_CC);
1177 }
1178 /* }}} */
1179 
sxe_get_debug_info(zval * object,int * is_temp TSRMLS_DC)1180 static HashTable * sxe_get_debug_info(zval *object, int *is_temp TSRMLS_DC) /* {{{ */
1181 {
1182 	*is_temp = 1;
1183 	return sxe_get_prop_hash(object, 1 TSRMLS_CC);
1184 }
1185 /* }}} */
1186 
sxe_objects_compare(zval * object1,zval * object2 TSRMLS_DC)1187 static int sxe_objects_compare(zval *object1, zval *object2 TSRMLS_DC) /* {{{ */
1188 {
1189 	php_sxe_object *sxe1;
1190 	php_sxe_object *sxe2;
1191 
1192 	sxe1 = php_sxe_fetch_object(object1 TSRMLS_CC);
1193 	sxe2 = php_sxe_fetch_object(object2 TSRMLS_CC);
1194 
1195 	if (sxe1->node == NULL) {
1196 		if (sxe2->node) {
1197 			return 1;
1198 		} else if (sxe1->document->ptr == sxe2->document->ptr) {
1199 			return 0;
1200 		}
1201 	} else {
1202 		return !(sxe1->node == sxe2->node);
1203 	}
1204 	return 1;
1205 }
1206 /* }}} */
1207 
1208 /* {{{ proto array SimpleXMLElement::xpath(string path)
1209    Runs XPath query on the XML data */
SXE_METHOD(xpath)1210 SXE_METHOD(xpath)
1211 {
1212 	php_sxe_object    *sxe;
1213 	zval              *value;
1214 	char              *query;
1215 	int                query_len;
1216 	int                i;
1217 	int                nsnbr = 0;
1218 	xmlNsPtr          *ns = NULL;
1219 	xmlXPathObjectPtr  retval;
1220 	xmlNodeSetPtr      result;
1221 	xmlNodePtr		   nodeptr;
1222 
1223 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &query, &query_len) == FAILURE) {
1224 		return;
1225 	}
1226 
1227 	sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1228 
1229 	if (sxe->iter.type == SXE_ITER_ATTRLIST) {
1230 		return; /* attributes don't have attributes */
1231 	}
1232 
1233 	if (!sxe->xpath) {
1234 		sxe->xpath = xmlXPathNewContext((xmlDocPtr) sxe->document->ptr);
1235 	}
1236 	if (!sxe->node) {
1237 		php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement((xmlDocPtr) sxe->document->ptr), NULL TSRMLS_CC);
1238 	}
1239 
1240 	nodeptr = php_sxe_get_first_node(sxe, sxe->node->node TSRMLS_CC);
1241 
1242 	sxe->xpath->node = nodeptr;
1243 
1244  	ns = xmlGetNsList((xmlDocPtr) sxe->document->ptr, nodeptr);
1245 	if (ns != NULL) {
1246 		while (ns[nsnbr] != NULL) {
1247 			nsnbr++;
1248 		}
1249 	}
1250 
1251 	sxe->xpath->namespaces = ns;
1252 	sxe->xpath->nsNr = nsnbr;
1253 
1254 	retval = xmlXPathEval((xmlChar *)query, sxe->xpath);
1255 	if (ns != NULL) {
1256 		xmlFree(ns);
1257 		sxe->xpath->namespaces = NULL;
1258 		sxe->xpath->nsNr = 0;
1259 	}
1260 
1261 	if (!retval) {
1262 		RETURN_FALSE;
1263 	}
1264 
1265 	result = retval->nodesetval;
1266 
1267 	array_init(return_value);
1268 
1269 	if (result != NULL) {
1270 		for (i = 0; i < result->nodeNr; ++i) {
1271 			nodeptr = result->nodeTab[i];
1272 			if (nodeptr->type == XML_TEXT_NODE || nodeptr->type == XML_ELEMENT_NODE || nodeptr->type == XML_ATTRIBUTE_NODE) {
1273 				MAKE_STD_ZVAL(value);
1274 				/**
1275 				 * Detect the case where the last selector is text(), simplexml
1276 				 * always accesses the text() child by default, therefore we assign
1277 				 * to the parent node.
1278 				 */
1279 				if (nodeptr->type == XML_TEXT_NODE) {
1280 					_node_as_zval(sxe, nodeptr->parent, value, SXE_ITER_NONE, NULL, NULL, 0 TSRMLS_CC);
1281 				} else if (nodeptr->type == XML_ATTRIBUTE_NODE) {
1282 					_node_as_zval(sxe, nodeptr->parent, value, SXE_ITER_ATTRLIST, (char*)nodeptr->name, nodeptr->ns ? (xmlChar *)nodeptr->ns->href : NULL, 0 TSRMLS_CC);
1283 				} else {
1284 					_node_as_zval(sxe, nodeptr, value, SXE_ITER_NONE, NULL, NULL, 0 TSRMLS_CC);
1285 				}
1286 
1287 				add_next_index_zval(return_value, value);
1288 			}
1289 		}
1290 	}
1291 
1292 	xmlXPathFreeObject(retval);
1293 }
1294 /* }}} */
1295 
1296 /* {{{ proto bool SimpleXMLElement::registerXPathNamespace(string prefix, string ns)
1297    Creates a prefix/ns context for the next XPath query */
SXE_METHOD(registerXPathNamespace)1298 SXE_METHOD(registerXPathNamespace)
1299 {
1300 	php_sxe_object    *sxe;
1301 	int prefix_len, ns_uri_len;
1302 	char *prefix, *ns_uri;
1303 
1304 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &prefix, &prefix_len, &ns_uri, &ns_uri_len) == FAILURE) {
1305 		return;
1306 	}
1307 
1308 	sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1309 	if (!sxe->xpath) {
1310 		sxe->xpath = xmlXPathNewContext((xmlDocPtr) sxe->document->ptr);
1311 	}
1312 
1313 	if (xmlXPathRegisterNs(sxe->xpath, (xmlChar *)prefix, (xmlChar *)ns_uri) != 0) {
1314 		RETURN_FALSE
1315 	}
1316 	RETURN_TRUE;
1317 }
1318 
1319 /* }}} */
1320 
1321 /* {{{ proto string SimpleXMLElement::asXML([string filename])
1322    Return a well-formed XML string based on SimpleXML element */
SXE_METHOD(asXML)1323 SXE_METHOD(asXML)
1324 {
1325 	php_sxe_object     *sxe;
1326 	xmlNodePtr          node;
1327 	xmlOutputBufferPtr  outbuf;
1328 	xmlChar            *strval;
1329 	int                 strval_len;
1330 	char               *filename;
1331 	int                 filename_len;
1332 
1333 	if (ZEND_NUM_ARGS() > 1) {
1334 		RETURN_FALSE;
1335 	}
1336 
1337 	if (ZEND_NUM_ARGS() == 1) {
1338 		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
1339 			RETURN_FALSE;
1340 		}
1341 
1342 		sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1343 		GET_NODE(sxe, node);
1344 		node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1345 
1346 		if (node) {
1347 			if (node->parent && (XML_DOCUMENT_NODE == node->parent->type)) {
1348 				int bytes;
1349 				bytes = xmlSaveFile(filename, (xmlDocPtr) sxe->document->ptr);
1350 				if (bytes == -1) {
1351 					RETURN_FALSE;
1352 				} else {
1353 					RETURN_TRUE;
1354 				}
1355 			} else {
1356 				outbuf = xmlOutputBufferCreateFilename(filename, NULL, 0);
1357 
1358 				if (outbuf == NULL) {
1359 					RETURN_FALSE;
1360 				}
1361 
1362 				xmlNodeDumpOutput(outbuf, (xmlDocPtr) sxe->document->ptr, node, 0, 0, NULL);
1363 				xmlOutputBufferClose(outbuf);
1364 				RETURN_TRUE;
1365 			}
1366 		} else {
1367 			RETURN_FALSE;
1368 		}
1369 	}
1370 
1371 	sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1372 	GET_NODE(sxe, node);
1373 	node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1374 
1375 	if (node) {
1376 		if (node->parent && (XML_DOCUMENT_NODE == node->parent->type)) {
1377 			xmlDocDumpMemoryEnc((xmlDocPtr) sxe->document->ptr, &strval, &strval_len, ((xmlDocPtr) sxe->document->ptr)->encoding);
1378 			RETVAL_STRINGL((char *)strval, strval_len, 1);
1379 			xmlFree(strval);
1380 		} else {
1381 			/* Should we be passing encoding information instead of NULL? */
1382 			outbuf = xmlAllocOutputBuffer(NULL);
1383 
1384 			if (outbuf == NULL) {
1385 				RETURN_FALSE;
1386 			}
1387 
1388 			xmlNodeDumpOutput(outbuf, (xmlDocPtr) sxe->document->ptr, node, 0, 0, ((xmlDocPtr) sxe->document->ptr)->encoding);
1389 			xmlOutputBufferFlush(outbuf);
1390 #ifdef LIBXML2_NEW_BUFFER
1391 			RETVAL_STRINGL((char *)xmlOutputBufferGetContent(outbuf), xmlOutputBufferGetSize(outbuf), 1);
1392 #else
1393 			RETVAL_STRINGL((char *)outbuf->buffer->content, outbuf->buffer->use, 1);
1394 #endif
1395 			xmlOutputBufferClose(outbuf);
1396 		}
1397 	} else {
1398 		RETVAL_FALSE;
1399 	}
1400 }
1401 /* }}} */
1402 
1403 #define SXE_NS_PREFIX(ns) (ns->prefix ? (char*)ns->prefix : "")
1404 
sxe_add_namespace_name(zval * return_value,xmlNsPtr ns)1405 static inline void sxe_add_namespace_name(zval *return_value, xmlNsPtr ns) /* {{{ */
1406 {
1407 	char *prefix = SXE_NS_PREFIX(ns);
1408 	if (zend_hash_exists(Z_ARRVAL_P(return_value), prefix, strlen(prefix) + 1) == 0) {
1409 		add_assoc_string(return_value, prefix, (char*)ns->href, 1);
1410 	}
1411 }
1412 /* }}} */
1413 
sxe_add_namespaces(php_sxe_object * sxe,xmlNodePtr node,zend_bool recursive,zval * return_value TSRMLS_DC)1414 static void sxe_add_namespaces(php_sxe_object *sxe, xmlNodePtr node, zend_bool recursive, zval *return_value TSRMLS_DC) /* {{{ */
1415 {
1416 	xmlAttrPtr  attr;
1417 
1418 	if (node->ns) {
1419 		sxe_add_namespace_name(return_value, node->ns);
1420 	}
1421 
1422 	attr = node->properties;
1423 	while (attr) {
1424 		if (attr->ns) {
1425 			sxe_add_namespace_name(return_value, attr->ns);
1426 		}
1427 		attr = attr->next;
1428 	}
1429 
1430 	if (recursive) {
1431 		node = node->children;
1432 		while (node) {
1433 			if (node->type == XML_ELEMENT_NODE) {
1434 				sxe_add_namespaces(sxe, node, recursive, return_value TSRMLS_CC);
1435 			}
1436 			node = node->next;
1437 		}
1438 	}
1439 } /* }}} */
1440 
1441 /* {{{ proto string SimpleXMLElement::getNamespaces([bool recursve])
1442    Return all namespaces in use */
SXE_METHOD(getNamespaces)1443 SXE_METHOD(getNamespaces)
1444 {
1445 	zend_bool           recursive = 0;
1446 	php_sxe_object     *sxe;
1447 	xmlNodePtr          node;
1448 
1449 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &recursive) == FAILURE) {
1450 		return;
1451 	}
1452 
1453 	array_init(return_value);
1454 
1455 	sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1456 	GET_NODE(sxe, node);
1457 	node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1458 
1459 	if (node) {
1460 		if (node->type == XML_ELEMENT_NODE) {
1461 			sxe_add_namespaces(sxe, node, recursive, return_value TSRMLS_CC);
1462 		} else if (node->type == XML_ATTRIBUTE_NODE && node->ns) {
1463 			sxe_add_namespace_name(return_value, node->ns);
1464 		}
1465 	}
1466 }
1467 /* }}} */
1468 
sxe_add_registered_namespaces(php_sxe_object * sxe,xmlNodePtr node,zend_bool recursive,zval * return_value TSRMLS_DC)1469 static void sxe_add_registered_namespaces(php_sxe_object *sxe, xmlNodePtr node, zend_bool recursive, zval *return_value TSRMLS_DC) /* {{{ */
1470 {
1471 	xmlNsPtr ns;
1472 
1473 	if (node->type == XML_ELEMENT_NODE) {
1474 		ns = node->nsDef;
1475 		while (ns != NULL) {
1476 			sxe_add_namespace_name(return_value, ns);
1477 			ns = ns->next;
1478 		}
1479 		if (recursive) {
1480 			node = node->children;
1481 			while (node) {
1482 				sxe_add_registered_namespaces(sxe, node, recursive, return_value TSRMLS_CC);
1483 				node = node->next;
1484 			}
1485 		}
1486 	}
1487 }
1488 /* }}} */
1489 
1490 /* {{{ proto string SimpleXMLElement::getDocNamespaces([bool recursive])
1491    Return all namespaces registered with document */
SXE_METHOD(getDocNamespaces)1492 SXE_METHOD(getDocNamespaces)
1493 {
1494 	zend_bool           recursive = 0;
1495 	php_sxe_object     *sxe;
1496 
1497 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &recursive) == FAILURE) {
1498 		return;
1499 	}
1500 
1501 	array_init(return_value);
1502 
1503 	sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1504 
1505 	sxe_add_registered_namespaces(sxe, xmlDocGetRootElement((xmlDocPtr)sxe->document->ptr), recursive, return_value TSRMLS_CC);
1506 }
1507 /* }}} */
1508 
1509 /* {{{ proto object SimpleXMLElement::children([string ns [, bool is_prefix]])
1510    Finds children of given node */
SXE_METHOD(children)1511 SXE_METHOD(children)
1512 {
1513 	php_sxe_object *sxe;
1514 	char           *nsprefix = NULL;
1515 	int             nsprefix_len = 0;
1516 	xmlNodePtr      node;
1517 	zend_bool       isprefix = 0;
1518 
1519 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!b", &nsprefix, &nsprefix_len, &isprefix) == FAILURE) {
1520 		return;
1521 	}
1522 
1523 	sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1524 
1525 	if (sxe->iter.type == SXE_ITER_ATTRLIST) {
1526 		return; /* attributes don't have attributes */
1527 	}
1528 
1529 	GET_NODE(sxe, node);
1530 	node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1531 
1532 	_node_as_zval(sxe, node, return_value, SXE_ITER_CHILD, NULL, (xmlChar *)nsprefix, isprefix TSRMLS_CC);
1533 
1534 }
1535 /* }}} */
1536 
1537 /* {{{ proto object SimpleXMLElement::getName()
1538    Finds children of given node */
SXE_METHOD(getName)1539 SXE_METHOD(getName)
1540 {
1541 	php_sxe_object *sxe;
1542 	xmlNodePtr      node;
1543 	int             namelen;
1544 
1545 	sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1546 
1547 	GET_NODE(sxe, node);
1548 	node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1549 	if (node) {
1550 		namelen = xmlStrlen(node->name);
1551 		RETURN_STRINGL((char*)node->name, namelen, 1);
1552 	} else {
1553 		RETURN_EMPTY_STRING();
1554 	}
1555 }
1556 /* }}} */
1557 
1558 /* {{{ proto array SimpleXMLElement::attributes([string ns [, bool is_prefix]])
1559    Identifies an element's attributes */
SXE_METHOD(attributes)1560 SXE_METHOD(attributes)
1561 {
1562 	php_sxe_object *sxe;
1563 	char           *nsprefix = NULL;
1564 	int             nsprefix_len = 0;
1565 	xmlNodePtr      node;
1566 	zend_bool       isprefix = 0;
1567 
1568 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!b", &nsprefix, &nsprefix_len, &isprefix) == FAILURE) {
1569 		return;
1570 	}
1571 
1572 	sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1573 	GET_NODE(sxe, node);
1574 
1575 	if (sxe->iter.type == SXE_ITER_ATTRLIST) {
1576 		return; /* attributes don't have attributes */
1577 	}
1578 
1579 	node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1580 
1581 	_node_as_zval(sxe, node, return_value, SXE_ITER_ATTRLIST, NULL, (xmlChar *)nsprefix, isprefix TSRMLS_CC);
1582 }
1583 /* }}} */
1584 
1585 /* {{{ proto void SimpleXMLElement::addChild(string qName [, string value [, string ns]])
1586    Add Element with optional namespace information */
SXE_METHOD(addChild)1587 SXE_METHOD(addChild)
1588 {
1589 	php_sxe_object *sxe;
1590 	char           *qname, *value = NULL, *nsuri = NULL;
1591 	int             qname_len, value_len = 0, nsuri_len = 0;
1592 	xmlNodePtr      node, newnode;
1593 	xmlNsPtr        nsptr = NULL;
1594 	xmlChar        *localname, *prefix = NULL;
1595 
1596 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!s!",
1597 		&qname, &qname_len, &value, &value_len, &nsuri, &nsuri_len) == FAILURE) {
1598 		return;
1599 	}
1600 
1601 	if (qname_len == 0) {
1602 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Element name is required");
1603 		return;
1604 	}
1605 
1606 	sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1607 	GET_NODE(sxe, node);
1608 
1609 	if (sxe->iter.type == SXE_ITER_ATTRLIST) {
1610 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element to attributes");
1611 		return;
1612 	}
1613 
1614 	node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1615 
1616 	if (node == NULL) {
1617 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add child. Parent is not a permanent member of the XML tree");
1618 		return;
1619 	}
1620 
1621 	localname = xmlSplitQName2((xmlChar *)qname, &prefix);
1622 	if (localname == NULL) {
1623 		localname = xmlStrdup((xmlChar *)qname);
1624 	}
1625 
1626 	newnode = xmlNewChild(node, NULL, localname, (xmlChar *)value);
1627 
1628 	if (nsuri != NULL) {
1629 		if (nsuri_len == 0) {
1630 			newnode->ns = NULL;
1631 			nsptr = xmlNewNs(newnode, (xmlChar *)nsuri, prefix);
1632 		} else {
1633 			nsptr = xmlSearchNsByHref(node->doc, node, (xmlChar *)nsuri);
1634 			if (nsptr == NULL) {
1635 				nsptr = xmlNewNs(newnode, (xmlChar *)nsuri, prefix);
1636 			}
1637 			newnode->ns = nsptr;
1638 		}
1639 	}
1640 
1641 	_node_as_zval(sxe, newnode, return_value, SXE_ITER_NONE, (char *)localname, prefix, 0 TSRMLS_CC);
1642 
1643 	xmlFree(localname);
1644 	if (prefix != NULL) {
1645 		xmlFree(prefix);
1646 	}
1647 }
1648 /* }}} */
1649 
1650 /* {{{ proto void SimpleXMLElement::addAttribute(string qName, string value [,string ns])
1651    Add Attribute with optional namespace information */
SXE_METHOD(addAttribute)1652 SXE_METHOD(addAttribute)
1653 {
1654 	php_sxe_object *sxe;
1655 	char           *qname, *value = NULL, *nsuri = NULL;
1656 	int             qname_len, value_len = 0, nsuri_len = 0;
1657 	xmlNodePtr      node;
1658 	xmlAttrPtr      attrp = NULL;
1659 	xmlNsPtr        nsptr = NULL;
1660 	xmlChar        *localname, *prefix = NULL;
1661 
1662 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s!",
1663 		&qname, &qname_len, &value, &value_len, &nsuri, &nsuri_len) == FAILURE) {
1664 		return;
1665 	}
1666 
1667 	if (qname_len == 0) {
1668 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attribute name is required");
1669 		return;
1670 	}
1671 
1672 	sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1673 	GET_NODE(sxe, node);
1674 
1675 	node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1676 
1677 	if (node && node->type != XML_ELEMENT_NODE) {
1678 		node = node->parent;
1679 	}
1680 
1681 	if (node == NULL) {
1682 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to locate parent Element");
1683 		return;
1684 	}
1685 
1686 	localname = xmlSplitQName2((xmlChar *)qname, &prefix);
1687 	if (localname == NULL) {
1688 		if (nsuri_len > 0) {
1689 			if (prefix != NULL) {
1690 				xmlFree(prefix);
1691 			}
1692 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attribute requires prefix for namespace");
1693 			return;
1694 		}
1695 		localname = xmlStrdup((xmlChar *)qname);
1696 	}
1697 
1698 	attrp = xmlHasNsProp(node, localname, (xmlChar *)nsuri);
1699 	if (attrp != NULL && attrp->type != XML_ATTRIBUTE_DECL) {
1700 		xmlFree(localname);
1701 		if (prefix != NULL) {
1702 			xmlFree(prefix);
1703 		}
1704 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attribute already exists");
1705 		return;
1706 	}
1707 
1708 	if (nsuri != NULL) {
1709 		nsptr = xmlSearchNsByHref(node->doc, node, (xmlChar *)nsuri);
1710 		if (nsptr == NULL) {
1711 			nsptr = xmlNewNs(node, (xmlChar *)nsuri, prefix);
1712 		}
1713 	}
1714 
1715 	attrp = xmlNewNsProp(node, nsptr, localname, (xmlChar *)value);
1716 
1717 	xmlFree(localname);
1718 	if (prefix != NULL) {
1719 		xmlFree(prefix);
1720 	}
1721 }
1722 /* }}} */
1723 
1724 /* {{{ cast_object()
1725  */
cast_object(zval * object,int type,char * contents TSRMLS_DC)1726 static int cast_object(zval *object, int type, char *contents TSRMLS_DC)
1727 {
1728 	if (contents) {
1729 		ZVAL_STRINGL(object, contents, strlen(contents), 1);
1730 	} else {
1731 		ZVAL_NULL(object);
1732 	}
1733 	Z_SET_REFCOUNT_P(object, 1);
1734 	Z_UNSET_ISREF_P(object);
1735 
1736 	switch (type) {
1737 		case IS_STRING:
1738 			convert_to_string(object);
1739 			break;
1740 		case IS_BOOL:
1741 			convert_to_boolean(object);
1742 			break;
1743 		case IS_LONG:
1744 			convert_to_long(object);
1745 			break;
1746 		case IS_DOUBLE:
1747 			convert_to_double(object);
1748 			break;
1749 		default:
1750 			return FAILURE;
1751 	}
1752 	return SUCCESS;
1753 }
1754 /* }}} */
1755 
1756 /* {{{ sxe_object_cast()
1757  */
sxe_object_cast(zval * readobj,zval * writeobj,int type TSRMLS_DC)1758 static int sxe_object_cast(zval *readobj, zval *writeobj, int type TSRMLS_DC)
1759 {
1760 	php_sxe_object *sxe;
1761 	xmlChar           *contents = NULL;
1762 	xmlNodePtr	    node;
1763 	int rv;
1764 	HashTable      *prop_hash;
1765 
1766 	sxe = php_sxe_fetch_object(readobj TSRMLS_CC);
1767 
1768 	if (type == IS_BOOL) {
1769 		node = php_sxe_get_first_node(sxe, NULL TSRMLS_CC);
1770 		prop_hash = sxe_get_prop_hash(readobj, 1 TSRMLS_CC);
1771 		INIT_PZVAL(writeobj);
1772 		ZVAL_BOOL(writeobj, node != NULL || zend_hash_num_elements(prop_hash) > 0);
1773 		zend_hash_destroy(prop_hash);
1774 		efree(prop_hash);
1775 		return SUCCESS;
1776 	}
1777 
1778 	if (sxe->iter.type != SXE_ITER_NONE) {
1779 		node = php_sxe_get_first_node(sxe, NULL TSRMLS_CC);
1780 		if (node) {
1781 			contents = xmlNodeListGetString((xmlDocPtr) sxe->document->ptr, node->children, 1);
1782 		}
1783 	} else {
1784 		if (!sxe->node) {
1785 			if (sxe->document) {
1786 				php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement((xmlDocPtr) sxe->document->ptr), NULL TSRMLS_CC);
1787 			}
1788 		}
1789 
1790 		if (sxe->node && sxe->node->node) {
1791 			if (sxe->node->node->children) {
1792 				contents = xmlNodeListGetString((xmlDocPtr) sxe->document->ptr, sxe->node->node->children, 1);
1793 			}
1794 		}
1795 	}
1796 
1797 	if (readobj == writeobj) {
1798 		INIT_PZVAL(writeobj);
1799 		zval_dtor(readobj);
1800 	}
1801 
1802 	rv = cast_object(writeobj, type, (char *)contents TSRMLS_CC);
1803 
1804 	if (contents) {
1805 		xmlFree(contents);
1806 	}
1807 	return rv;
1808 }
1809 /* }}} */
1810 
1811 /* {{{ proto object SimpleXMLElement::__toString() U
1812    Returns the string content */
SXE_METHOD(__toString)1813 SXE_METHOD(__toString)
1814 {
1815 	zval           *result;
1816 
1817 	ALLOC_INIT_ZVAL(result);
1818 
1819 	if (sxe_object_cast(getThis(), result, IS_STRING TSRMLS_CC) == SUCCESS) {
1820 		RETURN_ZVAL(result, 1, 1);
1821 	} else {
1822 		zval_ptr_dtor(&result);
1823 		RETURN_EMPTY_STRING();
1824 	}
1825 }
1826 /* }}} */
1827 
php_sxe_count_elements_helper(php_sxe_object * sxe,long * count TSRMLS_DC)1828 static int php_sxe_count_elements_helper(php_sxe_object *sxe, long *count TSRMLS_DC) /* {{{ */
1829 {
1830 	xmlNodePtr       node;
1831 	zval            *data;
1832 
1833 	*count = 0;
1834 
1835 	data = sxe->iter.data;
1836 	sxe->iter.data = NULL;
1837 
1838 	node = php_sxe_reset_iterator(sxe, 0 TSRMLS_CC);
1839 
1840 	while (node)
1841 	{
1842 		(*count)++;
1843 		node = php_sxe_iterator_fetch(sxe, node->next, 0 TSRMLS_CC);
1844 	}
1845 
1846 	if (sxe->iter.data) {
1847 		zval_ptr_dtor(&sxe->iter.data);
1848 	}
1849 	sxe->iter.data = data;
1850 
1851 	return SUCCESS;
1852 }
1853 /* }}} */
1854 
sxe_count_elements(zval * object,long * count TSRMLS_DC)1855 static int sxe_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */
1856 {
1857 	php_sxe_object  *intern;
1858 	intern = php_sxe_fetch_object(object TSRMLS_CC);
1859 	if (intern->fptr_count) {
1860 		zval *rv;
1861 		zend_call_method_with_0_params(&object, intern->zo.ce, &intern->fptr_count, "count", &rv);
1862 		if (rv) {
1863 			if (intern->tmp) {
1864 				zval_ptr_dtor(&intern->tmp);
1865 			}
1866 			MAKE_STD_ZVAL(intern->tmp);
1867 			ZVAL_ZVAL(intern->tmp, rv, 1, 1);
1868 			convert_to_long(intern->tmp);
1869 			*count = (long) Z_LVAL_P(intern->tmp);
1870 			return SUCCESS;
1871 		}
1872 		return FAILURE;
1873 	}
1874 	return php_sxe_count_elements_helper(intern, count TSRMLS_CC);
1875 }
1876 /* }}} */
1877 
1878 /* {{{ proto int SimpleXMLElement::count()
1879  Get number of child elements */
SXE_METHOD(count)1880 SXE_METHOD(count)
1881 {
1882 	long count = 0;
1883 	php_sxe_object *sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1884 
1885 	if (zend_parse_parameters_none() == FAILURE) {
1886 		return;
1887 	}
1888 
1889 	php_sxe_count_elements_helper(sxe, &count TSRMLS_CC);
1890 
1891 	RETURN_LONG(count);
1892 }
1893 /* }}} */
1894 
sxe_get_value(zval * z TSRMLS_DC)1895 static zval *sxe_get_value(zval *z TSRMLS_DC) /* {{{ */
1896 {
1897 	zval *retval;
1898 
1899 	MAKE_STD_ZVAL(retval);
1900 
1901 	if (sxe_object_cast(z, retval, IS_STRING TSRMLS_CC)==FAILURE) {
1902 		zend_error(E_ERROR, "Unable to cast node to string");
1903 		/* FIXME: Should not be fatal */
1904 	}
1905 
1906 	Z_SET_REFCOUNT_P(retval, 0);
1907 	return retval;
1908 }
1909 /* }}} */
1910 
1911 static zend_object_handlers sxe_object_handlers = { /* {{{ */
1912 	ZEND_OBJECTS_STORE_HANDLERS,
1913 	sxe_property_read,
1914 	sxe_property_write,
1915 	sxe_dimension_read,
1916 	sxe_dimension_write,
1917 	sxe_property_get_adr,
1918 	sxe_get_value,			/* get */
1919 	NULL,
1920 	sxe_property_exists,
1921 	sxe_property_delete,
1922 	sxe_dimension_exists,
1923 	sxe_dimension_delete,
1924 	sxe_get_properties,
1925 	NULL, /* zend_get_std_object_handlers()->get_method,*/
1926 	NULL, /* zend_get_std_object_handlers()->call_method,*/
1927 	NULL, /* zend_get_std_object_handlers()->get_constructor, */
1928 	NULL, /* zend_get_std_object_handlers()->get_class_entry,*/
1929 	NULL, /* zend_get_std_object_handlers()->get_class_name,*/
1930 	sxe_objects_compare,
1931 	sxe_object_cast,
1932 	sxe_count_elements,
1933 	sxe_get_debug_info
1934 };
1935 /* }}} */
1936 
1937 /* {{{ sxe_object_clone()
1938  */
1939 static void
sxe_object_clone(void * object,void ** clone_ptr TSRMLS_DC)1940 sxe_object_clone(void *object, void **clone_ptr TSRMLS_DC)
1941 {
1942 	php_sxe_object *sxe = (php_sxe_object *) object;
1943 	php_sxe_object *clone;
1944 	xmlNodePtr nodep = NULL;
1945 	xmlDocPtr docp = NULL;
1946 
1947 	clone = php_sxe_object_new(sxe->zo.ce TSRMLS_CC);
1948 	clone->document = sxe->document;
1949 	if (clone->document) {
1950 		clone->document->refcount++;
1951 		docp = clone->document->ptr;
1952 	}
1953 
1954 	clone->iter.isprefix = sxe->iter.isprefix;
1955 	if (sxe->iter.name != NULL) {
1956 		clone->iter.name = xmlStrdup((xmlChar *)sxe->iter.name);
1957 	}
1958 	if (sxe->iter.nsprefix != NULL) {
1959 		clone->iter.nsprefix = xmlStrdup((xmlChar *)sxe->iter.nsprefix);
1960 	}
1961 	clone->iter.type = sxe->iter.type;
1962 
1963 	if (sxe->node) {
1964 		nodep = xmlDocCopyNode(sxe->node->node, docp, 1);
1965 	}
1966 
1967 	php_libxml_increment_node_ptr((php_libxml_node_object *)clone, nodep, NULL TSRMLS_CC);
1968 
1969 	*clone_ptr = (void *) clone;
1970 }
1971 /* }}} */
1972 
1973 /* {{{ sxe_object_dtor()
1974  */
sxe_object_dtor(void * object,zend_object_handle handle TSRMLS_DC)1975 static void sxe_object_dtor(void *object, zend_object_handle handle TSRMLS_DC)
1976 {
1977 	/* dtor required to cleanup iterator related data properly */
1978 
1979 	php_sxe_object *sxe;
1980 
1981 	sxe = (php_sxe_object *) object;
1982 
1983 	if (sxe->iter.data) {
1984 		zval_ptr_dtor(&sxe->iter.data);
1985 		sxe->iter.data = NULL;
1986 	}
1987 
1988 	if (sxe->iter.name) {
1989 		xmlFree(sxe->iter.name);
1990 		sxe->iter.name = NULL;
1991 	}
1992 	if (sxe->iter.nsprefix) {
1993 		xmlFree(sxe->iter.nsprefix);
1994 		sxe->iter.nsprefix = NULL;
1995 	}
1996 	if (sxe->tmp) {
1997 		zval_ptr_dtor(&sxe->tmp);
1998 		sxe->tmp = NULL;
1999 	}
2000 }
2001 /* }}} */
2002 
2003 /* {{{ sxe_object_free_storage()
2004  */
sxe_object_free_storage(void * object TSRMLS_DC)2005 static void sxe_object_free_storage(void *object TSRMLS_DC)
2006 {
2007 	php_sxe_object *sxe;
2008 
2009 	sxe = (php_sxe_object *) object;
2010 
2011 #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)
2012 	zend_object_std_dtor(&sxe->zo TSRMLS_CC);
2013 #else
2014 	if (sxe->zo.guards) {
2015 		zend_hash_destroy(sxe->zo.guards);
2016 		FREE_HASHTABLE(sxe->zo.guards);
2017 	}
2018 
2019 	if (sxe->zo.properties) {
2020 		zend_hash_destroy(sxe->zo.properties);
2021 		FREE_HASHTABLE(sxe->zo.properties);
2022 	}
2023 #endif
2024 
2025 	php_libxml_node_decrement_resource((php_libxml_node_object *)sxe TSRMLS_CC);
2026 
2027 	if (sxe->xpath) {
2028 		xmlXPathFreeContext(sxe->xpath);
2029 	}
2030 
2031 	if (sxe->properties) {
2032 		zend_hash_destroy(sxe->properties);
2033 		FREE_HASHTABLE(sxe->properties);
2034 	}
2035 
2036 	efree(object);
2037 }
2038 /* }}} */
2039 
2040 /* {{{ php_sxe_object_new()
2041  */
php_sxe_object_new(zend_class_entry * ce TSRMLS_DC)2042 static php_sxe_object* php_sxe_object_new(zend_class_entry *ce TSRMLS_DC)
2043 {
2044 	php_sxe_object *intern;
2045 	zend_class_entry     *parent = ce;
2046 	int inherited = 0;
2047 
2048 	intern = ecalloc(1, sizeof(php_sxe_object));
2049 
2050 	intern->iter.type = SXE_ITER_NONE;
2051 	intern->iter.nsprefix = NULL;
2052 	intern->iter.name = NULL;
2053 	intern->fptr_count = NULL;
2054 
2055 #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)
2056 	zend_object_std_init(&intern->zo, ce TSRMLS_CC);
2057 #else
2058 	ALLOC_HASHTABLE(intern->zo.properties);
2059 	zend_hash_init(intern->zo.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
2060 
2061 	intern->zo.ce = ce;
2062 	intern->zo.guards = NULL;
2063 #endif
2064 
2065 	while (parent) {
2066 		if (parent == sxe_class_entry) {
2067 			break;
2068 		}
2069 
2070 		parent = parent->parent;
2071 		inherited = 1;
2072 	}
2073 
2074 	if (inherited) {
2075 		zend_hash_find(&ce->function_table, "count", sizeof("count"),(void **) &intern->fptr_count);
2076 		if (intern->fptr_count->common.scope == parent) {
2077 			intern->fptr_count = NULL;
2078 		}
2079 	}
2080 
2081 	return intern;
2082 }
2083 /* }}} */
2084 
2085 /* {{{ php_sxe_register_object
2086  */
2087 static zend_object_value
php_sxe_register_object(php_sxe_object * intern TSRMLS_DC)2088 php_sxe_register_object(php_sxe_object *intern TSRMLS_DC)
2089 {
2090 	zend_object_value rv;
2091 
2092 	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);
2093 	rv.handlers = (zend_object_handlers *) &sxe_object_handlers;
2094 
2095 	return rv;
2096 }
2097 /* }}} */
2098 
2099 /* {{{ sxe_object_new()
2100  */
2101 PHP_SXE_API zend_object_value
sxe_object_new(zend_class_entry * ce TSRMLS_DC)2102 sxe_object_new(zend_class_entry *ce TSRMLS_DC)
2103 {
2104 	php_sxe_object    *intern;
2105 
2106 	intern = php_sxe_object_new(ce TSRMLS_CC);
2107 	return php_sxe_register_object(intern TSRMLS_CC);
2108 }
2109 /* }}} */
2110 
2111 /* {{{ proto simplemxml_element simplexml_load_file(string filename [, string class_name [, int options [, string ns [, bool is_prefix]]]])
2112    Load a filename and return a simplexml_element object to allow for processing */
PHP_FUNCTION(simplexml_load_file)2113 PHP_FUNCTION(simplexml_load_file)
2114 {
2115 	php_sxe_object *sxe;
2116 	char           *filename;
2117 	int             filename_len;
2118 	xmlDocPtr       docp;
2119 	char           *ns = NULL;
2120 	int             ns_len = 0;
2121 	long            options = 0;
2122 	zend_class_entry *ce= sxe_class_entry;
2123 	zend_bool       isprefix = 0;
2124 
2125 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|C!lsb", &filename, &filename_len, &ce, &options, &ns, &ns_len, &isprefix) == FAILURE) {
2126 		return;
2127 	}
2128 
2129 	docp = xmlReadFile(filename, NULL, options);
2130 
2131 	if (! docp) {
2132 		RETURN_FALSE;
2133 	}
2134 
2135 	if (!ce) {
2136 		ce = sxe_class_entry;
2137 	}
2138 	sxe = php_sxe_object_new(ce TSRMLS_CC);
2139 	sxe->iter.nsprefix = ns_len ? xmlStrdup((xmlChar *)ns) : NULL;
2140 	sxe->iter.isprefix = isprefix;
2141 	php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp TSRMLS_CC);
2142 	php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL TSRMLS_CC);
2143 
2144 	return_value->type = IS_OBJECT;
2145 	return_value->value.obj = php_sxe_register_object(sxe TSRMLS_CC);
2146 }
2147 /* }}} */
2148 
2149 /* {{{ proto simplemxml_element simplexml_load_string(string data [, string class_name [, int options [, string ns [, bool is_prefix]]]])
2150    Load a string and return a simplexml_element object to allow for processing */
PHP_FUNCTION(simplexml_load_string)2151 PHP_FUNCTION(simplexml_load_string)
2152 {
2153 	php_sxe_object *sxe;
2154 	char           *data;
2155 	int             data_len;
2156 	xmlDocPtr       docp;
2157 	char           *ns = NULL;
2158 	int             ns_len = 0;
2159 	long            options = 0;
2160 	zend_class_entry *ce= sxe_class_entry;
2161 	zend_bool       isprefix = 0;
2162 
2163 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|C!lsb", &data, &data_len, &ce, &options, &ns, &ns_len, &isprefix) == FAILURE) {
2164 		return;
2165 	}
2166 
2167 	docp = xmlReadMemory(data, data_len, NULL, NULL, options);
2168 
2169 	if (! docp) {
2170 		RETURN_FALSE;
2171 	}
2172 
2173 	if (!ce) {
2174 		ce = sxe_class_entry;
2175 	}
2176 	sxe = php_sxe_object_new(ce TSRMLS_CC);
2177 	sxe->iter.nsprefix = ns_len ? xmlStrdup((xmlChar *)ns) : NULL;
2178 	sxe->iter.isprefix = isprefix;
2179 	php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp TSRMLS_CC);
2180 	php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL TSRMLS_CC);
2181 
2182 	return_value->type = IS_OBJECT;
2183 	return_value->value.obj = php_sxe_register_object(sxe TSRMLS_CC);
2184 }
2185 /* }}} */
2186 
2187 /* {{{ proto SimpleXMLElement::__construct(string data [, int options [, bool data_is_url [, string ns [, bool is_prefix]]]])
2188    SimpleXMLElement constructor */
SXE_METHOD(__construct)2189 SXE_METHOD(__construct)
2190 {
2191 	php_sxe_object *sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
2192 	char           *data, *ns = NULL;
2193 	int             data_len, ns_len = 0;
2194 	xmlDocPtr       docp;
2195 	long            options = 0;
2196 	zend_bool       is_url = 0, isprefix = 0;
2197 	zend_error_handling error_handling;
2198 
2199 	zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
2200 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lbsb", &data, &data_len, &options, &is_url, &ns, &ns_len, &isprefix) == FAILURE) {
2201 		zend_restore_error_handling(&error_handling TSRMLS_CC);
2202 		return;
2203 	}
2204 
2205 	zend_restore_error_handling(&error_handling TSRMLS_CC);
2206 
2207 	docp = is_url ? xmlReadFile(data, NULL, options) : xmlReadMemory(data, data_len, NULL, NULL, options);
2208 
2209 	if (!docp) {
2210 		((php_libxml_node_object *)sxe)->document = NULL;
2211 		zend_throw_exception(zend_exception_get_default(TSRMLS_C), "String could not be parsed as XML", 0 TSRMLS_CC);
2212 		return;
2213 	}
2214 
2215 	sxe->iter.nsprefix = ns_len ? xmlStrdup((xmlChar *)ns) : NULL;
2216 	sxe->iter.isprefix = isprefix;
2217 	php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp TSRMLS_CC);
2218 	php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL TSRMLS_CC);
2219 }
2220 /* }}} */
2221 
2222 zend_object_iterator_funcs php_sxe_iterator_funcs = { /* {{{ */
2223 	php_sxe_iterator_dtor,
2224 	php_sxe_iterator_valid,
2225 	php_sxe_iterator_current_data,
2226 	php_sxe_iterator_current_key,
2227 	php_sxe_iterator_move_forward,
2228 	php_sxe_iterator_rewind,
2229 };
2230 /* }}} */
2231 
php_sxe_iterator_fetch(php_sxe_object * sxe,xmlNodePtr node,int use_data TSRMLS_DC)2232 static xmlNodePtr php_sxe_iterator_fetch(php_sxe_object *sxe, xmlNodePtr node, int use_data TSRMLS_DC) /* {{{ */
2233 {
2234 	xmlChar *prefix  = sxe->iter.nsprefix;
2235 	int isprefix  = sxe->iter.isprefix;
2236 	int test_elem = sxe->iter.type == SXE_ITER_ELEMENT  && sxe->iter.name;
2237 	int test_attr = sxe->iter.type == SXE_ITER_ATTRLIST && sxe->iter.name;
2238 
2239 	while (node) {
2240 		SKIP_TEXT(node);
2241 		if (sxe->iter.type != SXE_ITER_ATTRLIST && node->type == XML_ELEMENT_NODE) {
2242 			if ((!test_elem || !xmlStrcmp(node->name, sxe->iter.name)) && match_ns(sxe, node, prefix, isprefix)) {
2243 				break;
2244 			}
2245 		} else if (node->type == XML_ATTRIBUTE_NODE) {
2246 			if ((!test_attr || !xmlStrcmp(node->name, sxe->iter.name)) && match_ns(sxe, node, prefix, isprefix)) {
2247 				break;
2248 			}
2249 		}
2250 next_iter:
2251 		node = node->next;
2252 	}
2253 
2254 	if (node && use_data) {
2255 		ALLOC_INIT_ZVAL(sxe->iter.data);
2256 		_node_as_zval(sxe, node, sxe->iter.data, SXE_ITER_NONE, NULL, prefix, isprefix TSRMLS_CC);
2257 	}
2258 
2259 	return node;
2260 }
2261 /* }}} */
2262 
php_sxe_reset_iterator(php_sxe_object * sxe,int use_data TSRMLS_DC)2263 static xmlNodePtr php_sxe_reset_iterator(php_sxe_object *sxe, int use_data TSRMLS_DC) /* {{{ */
2264 {
2265 	xmlNodePtr node;
2266 
2267 	if (sxe->iter.data) {
2268 		zval_ptr_dtor(&sxe->iter.data);
2269 		sxe->iter.data = NULL;
2270 	}
2271 
2272 	GET_NODE(sxe, node)
2273 
2274 	if (node) {
2275 		switch (sxe->iter.type) {
2276 			case SXE_ITER_ELEMENT:
2277 			case SXE_ITER_CHILD:
2278 			case SXE_ITER_NONE:
2279 				node = node->children;
2280 				break;
2281 			case SXE_ITER_ATTRLIST:
2282 				node = (xmlNodePtr) node->properties;
2283 		}
2284 		return php_sxe_iterator_fetch(sxe, node, use_data TSRMLS_CC);
2285 	}
2286 	return NULL;
2287 }
2288 /* }}} */
2289 
php_sxe_get_iterator(zend_class_entry * ce,zval * object,int by_ref TSRMLS_DC)2290 zend_object_iterator *php_sxe_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
2291 {
2292 	php_sxe_iterator *iterator;
2293 
2294 	if (by_ref) {
2295 		zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
2296 	}
2297 	iterator = emalloc(sizeof(php_sxe_iterator));
2298 
2299 	Z_ADDREF_P(object);
2300 	iterator->intern.data = (void*)object;
2301 	iterator->intern.funcs = &php_sxe_iterator_funcs;
2302 	iterator->sxe = php_sxe_fetch_object(object TSRMLS_CC);
2303 
2304 	return (zend_object_iterator*)iterator;
2305 }
2306 /* }}} */
2307 
php_sxe_iterator_dtor(zend_object_iterator * iter TSRMLS_DC)2308 static void php_sxe_iterator_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
2309 {
2310 	php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2311 
2312 	/* cleanup handled in sxe_object_dtor as we dont always have an iterator wrapper */
2313 	if (iterator->intern.data) {
2314 		zval_ptr_dtor((zval**)&iterator->intern.data);
2315 	}
2316 
2317 	efree(iterator);
2318 }
2319 /* }}} */
2320 
php_sxe_iterator_valid(zend_object_iterator * iter TSRMLS_DC)2321 static int php_sxe_iterator_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
2322 {
2323 	php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2324 
2325 	return iterator->sxe->iter.data ? SUCCESS : FAILURE;
2326 }
2327 /* }}} */
2328 
php_sxe_iterator_current_data(zend_object_iterator * iter,zval *** data TSRMLS_DC)2329 static void php_sxe_iterator_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */
2330 {
2331 	php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2332 
2333 	*data = &iterator->sxe->iter.data;
2334 }
2335 /* }}} */
2336 
php_sxe_iterator_current_key(zend_object_iterator * iter,char ** str_key,uint * str_key_len,ulong * int_key TSRMLS_DC)2337 static int php_sxe_iterator_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
2338 {
2339 	zval *curobj;
2340 	xmlNodePtr curnode = NULL;
2341 	php_sxe_object *intern;
2342 	int namelen;
2343 
2344 	php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2345 	curobj = iterator->sxe->iter.data;
2346 
2347 	intern = (php_sxe_object *)zend_object_store_get_object(curobj TSRMLS_CC);
2348 	if (intern != NULL && intern->node != NULL) {
2349 		curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->node)->node;
2350 	}
2351 	if (!curnode) {
2352 		return HASH_KEY_NON_EXISTANT;
2353 	}
2354 
2355 	namelen = xmlStrlen(curnode->name);
2356 	*str_key = estrndup((char *)curnode->name, namelen);
2357 	*str_key_len = namelen + 1;
2358 	return HASH_KEY_IS_STRING;
2359 
2360 }
2361 /* }}} */
2362 
php_sxe_move_forward_iterator(php_sxe_object * sxe TSRMLS_DC)2363 PHP_SXE_API void php_sxe_move_forward_iterator(php_sxe_object *sxe TSRMLS_DC) /* {{{ */
2364 {
2365 	xmlNodePtr      node = NULL;
2366 	php_sxe_object  *intern;
2367 
2368 	if (sxe->iter.data) {
2369 		intern = (php_sxe_object *)zend_object_store_get_object(sxe->iter.data TSRMLS_CC);
2370 		GET_NODE(intern, node)
2371 		zval_ptr_dtor(&sxe->iter.data);
2372 		sxe->iter.data = NULL;
2373 	}
2374 
2375 	if (node) {
2376 		php_sxe_iterator_fetch(sxe, node->next, 1 TSRMLS_CC);
2377 	}
2378 }
2379 /* }}} */
2380 
php_sxe_iterator_move_forward(zend_object_iterator * iter TSRMLS_DC)2381 static void php_sxe_iterator_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
2382 {
2383 	php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2384 	php_sxe_move_forward_iterator(iterator->sxe TSRMLS_CC);
2385 }
2386 /* }}} */
2387 
php_sxe_iterator_rewind(zend_object_iterator * iter TSRMLS_DC)2388 static void php_sxe_iterator_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
2389 {
2390 	php_sxe_object	*sxe;
2391 
2392 	php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2393 	sxe = iterator->sxe;
2394 
2395 	php_sxe_reset_iterator(sxe, 1 TSRMLS_CC);
2396 }
2397 /* }}} */
2398 
simplexml_export_node(zval * object TSRMLS_DC)2399 void *simplexml_export_node(zval *object TSRMLS_DC) /* {{{ */
2400 {
2401 	php_sxe_object *sxe;
2402 	xmlNodePtr node;
2403 
2404 	sxe = php_sxe_fetch_object(object TSRMLS_CC);
2405 	GET_NODE(sxe, node);
2406 	return php_sxe_get_first_node(sxe, node TSRMLS_CC);
2407 }
2408 /* }}} */
2409 
2410 /* {{{ proto simplemxml_element simplexml_import_dom(domNode node [, string class_name])
2411    Get a simplexml_element object from dom to allow for processing */
PHP_FUNCTION(simplexml_import_dom)2412 PHP_FUNCTION(simplexml_import_dom)
2413 {
2414 	php_sxe_object *sxe;
2415 	zval *node;
2416 	php_libxml_node_object *object;
2417 	xmlNodePtr		nodep = NULL;
2418 	zend_class_entry *ce= sxe_class_entry;
2419 
2420 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o|C!", &node, &ce) == FAILURE) {
2421 		return;
2422 	}
2423 
2424 	object = (php_libxml_node_object *)zend_object_store_get_object(node TSRMLS_CC);
2425 
2426 	nodep = php_libxml_import_node(node TSRMLS_CC);
2427 
2428 	if (nodep) {
2429 		if (nodep->doc == NULL) {
2430 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Imported Node must have associated Document");
2431 			RETURN_NULL();
2432 		}
2433 		if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
2434 			nodep = xmlDocGetRootElement((xmlDocPtr) nodep);
2435 		}
2436 	}
2437 
2438 	if (nodep && nodep->type == XML_ELEMENT_NODE) {
2439 		if (!ce) {
2440 			ce = sxe_class_entry;
2441 		}
2442 		sxe = php_sxe_object_new(ce TSRMLS_CC);
2443 		sxe->document = object->document;
2444 		php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, nodep->doc TSRMLS_CC);
2445 		php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, nodep, NULL TSRMLS_CC);
2446 
2447 		return_value->type = IS_OBJECT;
2448 		return_value->value.obj = php_sxe_register_object(sxe TSRMLS_CC);
2449 	} else {
2450 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Nodetype to import");
2451 		RETVAL_NULL();
2452 	}
2453 }
2454 /* }}} */
2455 
2456 /* {{{ arginfo */
2457 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexml_load_file, 0, 0, 1)
2458 	ZEND_ARG_INFO(0, filename)
2459 	ZEND_ARG_INFO(0, class_name)
2460 	ZEND_ARG_INFO(0, options)
2461 	ZEND_ARG_INFO(0, ns)
2462 	ZEND_ARG_INFO(0, is_prefix)
2463 ZEND_END_ARG_INFO()
2464 
2465 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexml_load_string, 0, 0, 1)
2466 	ZEND_ARG_INFO(0, data)
2467 	ZEND_ARG_INFO(0, class_name)
2468 	ZEND_ARG_INFO(0, options)
2469 	ZEND_ARG_INFO(0, ns)
2470 	ZEND_ARG_INFO(0, is_prefix)
2471 ZEND_END_ARG_INFO()
2472 
2473 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexml_import_dom, 0, 0, 1)
2474 	ZEND_ARG_INFO(0, node)
2475 	ZEND_ARG_INFO(0, class_name)
2476 ZEND_END_ARG_INFO()
2477 
2478 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_xpath, 0, 0, 1)
2479 	ZEND_ARG_INFO(0, path)
2480 ZEND_END_ARG_INFO()
2481 
2482 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_registerxpathnamespace, 0, 0, 2)
2483 	ZEND_ARG_INFO(0, prefix)
2484 	ZEND_ARG_INFO(0, ns)
2485 ZEND_END_ARG_INFO()
2486 
2487 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_asxml, 0, 0, 0)
2488 	ZEND_ARG_INFO(0, filename)
2489 ZEND_END_ARG_INFO()
2490 
2491 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_getnamespaces, 0, 0, 0)
2492 	ZEND_ARG_INFO(0, recursve)
2493 ZEND_END_ARG_INFO()
2494 
2495 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_children, 0, 0, 0)
2496 	ZEND_ARG_INFO(0, ns)
2497 	ZEND_ARG_INFO(0, is_prefix)
2498 ZEND_END_ARG_INFO()
2499 
2500 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement__construct, 0, 0, 1)
2501 	ZEND_ARG_INFO(0, data)
2502 	ZEND_ARG_INFO(0, options)
2503 	ZEND_ARG_INFO(0, data_is_url)
2504 	ZEND_ARG_INFO(0, ns)
2505 	ZEND_ARG_INFO(0, is_prefix)
2506 ZEND_END_ARG_INFO()
2507 
2508 ZEND_BEGIN_ARG_INFO(arginfo_simplexmlelement__void, 0)
2509 ZEND_END_ARG_INFO()
2510 
2511 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_addchild, 0, 0, 1)
2512 	ZEND_ARG_INFO(0, name)
2513 	ZEND_ARG_INFO(0, value)
2514 	ZEND_ARG_INFO(0, ns)
2515 ZEND_END_ARG_INFO()
2516 /* }}} */
2517 
2518 const zend_function_entry simplexml_functions[] = { /* {{{ */
2519 	PHP_FE(simplexml_load_file, 	arginfo_simplexml_load_file)
2520 	PHP_FE(simplexml_load_string,	arginfo_simplexml_load_string)
2521 	PHP_FE(simplexml_import_dom,	arginfo_simplexml_import_dom)
2522 	PHP_FE_END
2523 };
2524 /* }}} */
2525 
2526 static const zend_module_dep simplexml_deps[] = { /* {{{ */
2527 	ZEND_MOD_REQUIRED("libxml")
2528 	ZEND_MOD_REQUIRED("spl")
2529 	ZEND_MOD_END
2530 };
2531 /* }}} */
2532 
2533 zend_module_entry simplexml_module_entry = { /* {{{ */
2534 	STANDARD_MODULE_HEADER_EX, NULL,
2535 	simplexml_deps,
2536 	"SimpleXML",
2537 	simplexml_functions,
2538 	PHP_MINIT(simplexml),
2539 	PHP_MSHUTDOWN(simplexml),
2540 	NULL,
2541 	NULL,
2542 	PHP_MINFO(simplexml),
2543 	"0.1",
2544 	STANDARD_MODULE_PROPERTIES
2545 };
2546 /* }}} */
2547 
2548 #ifdef COMPILE_DL_SIMPLEXML
2549 ZEND_GET_MODULE(simplexml)
2550 #endif
2551 
2552 /* the method table */
2553 /* each method can have its own parameters and visibility */
2554 static const zend_function_entry sxe_functions[] = { /* {{{ */
2555 	SXE_ME(__construct,            arginfo_simplexmlelement__construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) /* must be called */
2556 	SXE_ME(asXML,                  arginfo_simplexmlelement_asxml, ZEND_ACC_PUBLIC)
2557 	SXE_MALIAS(saveXML, asXML,	   arginfo_simplexmlelement_asxml, ZEND_ACC_PUBLIC)
2558 	SXE_ME(xpath,                  arginfo_simplexmlelement_xpath, ZEND_ACC_PUBLIC)
2559 	SXE_ME(registerXPathNamespace, arginfo_simplexmlelement_registerxpathnamespace, ZEND_ACC_PUBLIC)
2560 	SXE_ME(attributes,             arginfo_simplexmlelement_children, ZEND_ACC_PUBLIC)
2561 	SXE_ME(children,               arginfo_simplexmlelement_children, ZEND_ACC_PUBLIC)
2562 	SXE_ME(getNamespaces,          arginfo_simplexmlelement_getnamespaces, ZEND_ACC_PUBLIC)
2563 	SXE_ME(getDocNamespaces,       arginfo_simplexmlelement_getnamespaces, ZEND_ACC_PUBLIC)
2564 	SXE_ME(getName,                arginfo_simplexmlelement__void, ZEND_ACC_PUBLIC)
2565 	SXE_ME(addChild,               arginfo_simplexmlelement_addchild, ZEND_ACC_PUBLIC)
2566 	SXE_ME(addAttribute,           arginfo_simplexmlelement_addchild, ZEND_ACC_PUBLIC)
2567 	SXE_ME(__toString,             arginfo_simplexmlelement__void, ZEND_ACC_PUBLIC)
2568 	SXE_ME(count,                  arginfo_simplexmlelement__void, ZEND_ACC_PUBLIC)
2569 	PHP_FE_END
2570 };
2571 /* }}} */
2572 
2573 /* {{{ PHP_MINIT_FUNCTION(simplexml)
2574  */
PHP_MINIT_FUNCTION(simplexml)2575 PHP_MINIT_FUNCTION(simplexml)
2576 {
2577 	zend_class_entry sxe;
2578 
2579 	INIT_CLASS_ENTRY(sxe, "SimpleXMLElement", sxe_functions);
2580 	sxe.create_object = sxe_object_new;
2581 	sxe_class_entry = zend_register_internal_class(&sxe TSRMLS_CC);
2582 	sxe_class_entry->get_iterator = php_sxe_get_iterator;
2583 	sxe_class_entry->iterator_funcs.funcs = &php_sxe_iterator_funcs;
2584 	zend_class_implements(sxe_class_entry TSRMLS_CC, 1, zend_ce_traversable);
2585 	sxe_object_handlers.get_method = zend_get_std_object_handlers()->get_method;
2586 	sxe_object_handlers.get_constructor = zend_get_std_object_handlers()->get_constructor;
2587 	sxe_object_handlers.get_class_entry = zend_get_std_object_handlers()->get_class_entry;
2588 	sxe_object_handlers.get_class_name = zend_get_std_object_handlers()->get_class_name;
2589 	sxe_class_entry->serialize = zend_class_serialize_deny;
2590 	sxe_class_entry->unserialize = zend_class_unserialize_deny;
2591 
2592 	php_libxml_register_export(sxe_class_entry, simplexml_export_node);
2593 
2594 	PHP_MINIT(sxe)(INIT_FUNC_ARGS_PASSTHRU);
2595 
2596 	return SUCCESS;
2597 }
2598 /* }}} */
2599 
2600 /* {{{ PHP_MSHUTDOWN_FUNCTION(simplexml)
2601  */
PHP_MSHUTDOWN_FUNCTION(simplexml)2602 PHP_MSHUTDOWN_FUNCTION(simplexml)
2603 {
2604 	sxe_class_entry = NULL;
2605 	return SUCCESS;
2606 }
2607 /* }}} */
2608 
2609 /* {{{ PHP_MINFO_FUNCTION(simplexml)
2610  */
PHP_MINFO_FUNCTION(simplexml)2611 PHP_MINFO_FUNCTION(simplexml)
2612 {
2613 	php_info_print_table_start();
2614 	php_info_print_table_header(2, "Simplexml support", "enabled");
2615 	php_info_print_table_row(2, "Revision", "$Id: 02ab7893b36d51e9c59da77d7e287eb3b35e1e32 $");
2616 	php_info_print_table_row(2, "Schema support",
2617 #ifdef LIBXML_SCHEMAS_ENABLED
2618 		"enabled");
2619 #else
2620 		"not available");
2621 #endif
2622 	php_info_print_table_end();
2623 }
2624 /* }}} */
2625 
2626 #endif
2627 
2628 /**
2629  * Local Variables:
2630  * c-basic-offset: 4
2631  * tab-width: 4
2632  * indent-tabs-mode: t
2633  * End:
2634  * vim600: fdm=marker
2635  * vim: noet sw=4 ts=4
2636  */
2637