root/ext/simplexml/simplexml.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sxe_get_element_class_entry
  2. _node_as_zval
  3. php_sxe_get_first_node
  4. match_ns
  5. sxe_get_element_by_offset
  6. sxe_find_element_by_name
  7. sxe_get_element_by_name
  8. sxe_prop_dim_read
  9. sxe_property_read
  10. sxe_dimension_read
  11. change_node_zval
  12. sxe_prop_dim_write
  13. sxe_property_write
  14. sxe_dimension_write
  15. sxe_property_get_adr
  16. sxe_prop_dim_exists
  17. sxe_property_exists
  18. sxe_dimension_exists
  19. sxe_prop_dim_delete
  20. sxe_property_delete
  21. sxe_dimension_delete
  22. sxe_xmlNodeListGetString
  23. _get_base_node_value
  24. sxe_properties_add
  25. sxe_prop_is_empty
  26. sxe_get_prop_hash
  27. sxe_get_gc
  28. sxe_get_properties
  29. sxe_get_debug_info
  30. sxe_objects_compare
  31. SXE_METHOD
  32. SXE_METHOD
  33. SXE_METHOD
  34. sxe_add_namespace_name
  35. sxe_add_namespaces
  36. SXE_METHOD
  37. sxe_add_registered_namespaces
  38. SXE_METHOD
  39. SXE_METHOD
  40. SXE_METHOD
  41. SXE_METHOD
  42. SXE_METHOD
  43. SXE_METHOD
  44. cast_object
  45. sxe_object_cast_ex
  46. sxe_object_cast
  47. SXE_METHOD
  48. php_sxe_count_elements_helper
  49. sxe_count_elements
  50. SXE_METHOD
  51. sxe_get_value
  52. sxe_object_clone
  53. sxe_object_dtor
  54. sxe_object_free_storage
  55. php_sxe_find_fptr_count
  56. php_sxe_object_new
  57. sxe_object_new
  58. PHP_FUNCTION
  59. PHP_FUNCTION
  60. SXE_METHOD
  61. php_sxe_iterator_fetch
  62. php_sxe_reset_iterator
  63. php_sxe_get_iterator
  64. php_sxe_iterator_dtor
  65. php_sxe_iterator_valid
  66. php_sxe_iterator_current_data
  67. php_sxe_iterator_current_key
  68. php_sxe_move_forward_iterator
  69. php_sxe_iterator_move_forward
  70. php_sxe_iterator_rewind
  71. simplexml_export_node
  72. PHP_FUNCTION
  73. PHP_MINIT_FUNCTION
  74. PHP_MSHUTDOWN_FUNCTION
  75. PHP_MINFO_FUNCTION

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

/* [<][>][^][v][top][bottom][index][help] */