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