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