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