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