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