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