diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c index a00b152f9c089..2c149e14d34d0 100644 --- a/ext/simplexml/simplexml.c +++ b/ext/simplexml/simplexml.c @@ -41,6 +41,11 @@ PHP_SXE_API zend_class_entry *sxe_get_element_class_entry(void) /* {{{ */ } /* }}} */ +typedef enum sxe_access_mode { + SXE_ACCESS_ELEMENTS, + SXE_ACCESS_ATTRIBS, +} sxe_access_mode; + static php_sxe_object* php_sxe_object_new(zend_class_entry *ce, zend_function *fptr_count); static xmlNodePtr php_sxe_reset_iterator(php_sxe_object *sxe); static xmlNodePtr php_sxe_reset_iterator_no_clear_iter_data(php_sxe_object *sxe, int use_data); @@ -207,7 +212,7 @@ static xmlNodePtr sxe_get_element_by_name(php_sxe_object *sxe, xmlNodePtr node, /* }}} */ /* {{{ sxe_prop_dim_read() */ -static zval *sxe_prop_dim_read(zend_object *object, zval *member, bool elements, bool attribs, int type, zval *rv) +static zval *sxe_prop_dim_read(zend_object *object, zval *member, sxe_access_mode access_mode, int type, zval *rv) { php_sxe_object *sxe; zend_string *name; @@ -231,8 +236,7 @@ static zval *sxe_prop_dim_read(zend_object *object, zval *member, bool elements, if (Z_TYPE_P(member) == IS_LONG) { if (sxe->iter.type != SXE_ITER_ATTRLIST) { long_dim: - attribs = 0; - elements = 1; + access_mode = SXE_ACCESS_ELEMENTS; } name = NULL; } else { @@ -251,8 +255,7 @@ static zval *sxe_prop_dim_read(zend_object *object, zval *member, bool elements, GET_NODE(sxe, node); if (sxe->iter.type == SXE_ITER_ATTRLIST) { - attribs = 1; - elements = 0; + access_mode = SXE_ACCESS_ATTRIBS; node = php_sxe_get_first_node_non_destructive(sxe, node); attr = (xmlAttrPtr)node; test = sxe->iter.name != NULL; @@ -268,10 +271,10 @@ static zval *sxe_prop_dim_read(zend_object *object, zval *member, bool elements, } } - ZVAL_UNDEF(rv); + ZVAL_NULL(rv); if (node) { - if (attribs) { + if (access_mode == SXE_ACCESS_ATTRIBS) { if (Z_TYPE_P(member) != IS_LONG || sxe->iter.type == SXE_ITER_ATTRLIST) { if (Z_TYPE_P(member) == IS_LONG) { while (attr && nodendx <= Z_LVAL_P(member)) { @@ -294,9 +297,7 @@ static zval *sxe_prop_dim_read(zend_object *object, zval *member, bool elements, } } } - } - - if (elements) { + } else { if (!sxe->node) { php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, node, NULL); } @@ -338,10 +339,6 @@ static zval *sxe_prop_dim_read(zend_object *object, zval *member, bool elements, zval_ptr_dtor_str(&tmp_zv); } - if (Z_ISUNDEF_P(rv)) { - ZVAL_NULL(rv); - } - return rv; } /* }}} */ @@ -351,14 +348,14 @@ static zval *sxe_property_read(zend_object *object, zend_string *name, int type, { zval member; ZVAL_STR(&member, name); - return sxe_prop_dim_read(object, &member, 1, 0, type, rv); + return sxe_prop_dim_read(object, &member, SXE_ACCESS_ELEMENTS, type, rv); } /* }}} */ /* {{{ sxe_dimension_read() */ static zval *sxe_dimension_read(zend_object *object, zval *offset, int type, zval *rv) { - return sxe_prop_dim_read(object, offset, 0, 1, type, rv); + return sxe_prop_dim_read(object, offset, SXE_ACCESS_ATTRIBS, type, rv); } /* }}} */ @@ -375,7 +372,7 @@ static void change_node_zval(xmlNodePtr node, zend_string *value) /* }}} */ /* {{{ sxe_property_write() */ -static zval *sxe_prop_dim_write(zend_object *object, zval *member, zval *value, bool elements, bool attribs, xmlNodePtr *pnewnode) +static zval *sxe_prop_dim_write(zend_object *object, zval *member, zval *value, sxe_access_mode access_mode, xmlNodePtr *pnewnode) { php_sxe_object *sxe; xmlNodePtr node; @@ -409,8 +406,7 @@ static zval *sxe_prop_dim_write(zend_object *object, zval *member, zval *value, if (Z_TYPE_P(member) == IS_LONG) { if (sxe->iter.type != SXE_ITER_ATTRLIST) { long_dim: - attribs = 0; - elements = 1; + access_mode = SXE_ACCESS_ELEMENTS; } } else { if (Z_TYPE_P(member) != IS_STRING) { @@ -425,7 +421,7 @@ static zval *sxe_prop_dim_write(zend_object *object, zval *member, zval *value, } if (!Z_STRLEN_P(member)) { - zend_value_error("Cannot create %s with an empty name", attribs ? "attribute" : "element"); + zend_value_error("Cannot create %s with an empty name", access_mode == SXE_ACCESS_ATTRIBS ? "attribute" : "element"); if (member == &tmp_zv) { zval_ptr_dtor_str(&tmp_zv); } @@ -437,8 +433,7 @@ static zval *sxe_prop_dim_write(zend_object *object, zval *member, zval *value, GET_NODE(sxe, node); if (sxe->iter.type == SXE_ITER_ATTRLIST) { - attribs = 1; - elements = 0; + access_mode = SXE_ACCESS_ATTRIBS; node = php_sxe_get_first_node_non_destructive(sxe, node); attr = (xmlAttrPtr)node; test = sxe->iter.name != NULL; @@ -456,7 +451,7 @@ static zval *sxe_prop_dim_write(zend_object *object, zval *member, zval *value, zend_value_error("Cannot append to an attribute list"); return &EG(error_zval); } - if (attribs && !node && sxe->iter.type == SXE_ITER_ELEMENT) { + if (access_mode == SXE_ACCESS_ATTRIBS && !node && sxe->iter.type == SXE_ITER_ELEMENT) { node = xmlNewChild(mynode, mynode->ns, BAD_CAST ZSTR_VAL(sxe->iter.name), NULL); attr = node->properties; } @@ -489,7 +484,7 @@ static zval *sxe_prop_dim_write(zend_object *object, zval *member, zval *value, if (member == &tmp_zv) { zval_ptr_dtor_str(&tmp_zv); } - zend_type_error("It's not possible to assign a complex type to %s, %s given", attribs ? "attributes" : "properties", zend_zval_value_name(value)); + zend_type_error("It's not possible to assign a complex type to %s, %s given", access_mode == SXE_ACCESS_ATTRIBS ? "attributes" : "properties", zend_zval_value_name(value)); return &EG(error_zval); } } @@ -497,7 +492,7 @@ static zval *sxe_prop_dim_write(zend_object *object, zval *member, zval *value, if (node) { php_libxml_invalidate_node_list_cache_from_doc(node->doc); - if (attribs) { + if (access_mode == SXE_ACCESS_ATTRIBS) { if (Z_TYPE_P(member) == IS_LONG) { while (attr && nodendx <= Z_LVAL_P(member)) { if ((!test || xmlStrEqual(attr->name, BAD_CAST ZSTR_VAL(sxe->iter.name))) && match_ns((xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) { @@ -520,10 +515,7 @@ static zval *sxe_prop_dim_write(zend_object *object, zval *member, zval *value, attr = attr->next; } } - - } - - if (elements) { + } else { if (!member || Z_TYPE_P(member) == IS_LONG) { if (node->type == XML_ATTRIBUTE_NODE) { zend_throw_error(NULL, "Cannot create duplicate attribute"); @@ -575,7 +567,7 @@ static zval *sxe_prop_dim_write(zend_object *object, zval *member, zval *value, } else if (counter > 1) { php_error_docref(NULL, E_WARNING, "Cannot assign to an array of nodes (duplicate subnodes or attr detected)"); value = &EG(error_zval); - } else if (elements) { + } else if (access_mode == SXE_ACCESS_ELEMENTS) { if (!node) { if (!member || Z_TYPE_P(member) == IS_LONG) { newnode = xmlNewTextChild(mynode->parent, mynode->ns, mynode->name, value_str ? (xmlChar *)ZSTR_VAL(value_str) : NULL); @@ -591,7 +583,7 @@ static zval *sxe_prop_dim_write(zend_object *object, zval *member, zval *value, } newnode = xmlNewTextChild(mynode->parent, mynode->ns, mynode->name, value_str ? (xmlChar *)ZSTR_VAL(value_str) : NULL); } - } else if (attribs) { + } else { if (Z_TYPE_P(member) == IS_LONG) { php_error_docref(NULL, E_WARNING, "Cannot change attribute number " ZEND_LONG_FMT " when only %d attributes exist", Z_LVAL_P(member), nodendx); } else { @@ -618,7 +610,7 @@ static zval *sxe_property_write(zend_object *object, zend_string *name, zval *va { zval member; ZVAL_STR(&member, name); - zval *retval = sxe_prop_dim_write(object, &member, value, 1, 0, NULL); + zval *retval = sxe_prop_dim_write(object, &member, value, SXE_ACCESS_ELEMENTS, NULL); return retval == &EG(error_zval) ? &EG(uninitialized_zval) : retval; } /* }}} */ @@ -626,7 +618,7 @@ static zval *sxe_property_write(zend_object *object, zend_string *name, zval *va /* {{{ sxe_dimension_write() */ static void sxe_dimension_write(zend_object *object, zval *offset, zval *value) { - sxe_prop_dim_write(object, offset, value, 0, 1, NULL); + sxe_prop_dim_write(object, offset, value, SXE_ACCESS_ATTRIBS, NULL); } /* }}} */ @@ -650,7 +642,7 @@ static zval *sxe_property_get_adr(zend_object *object, zend_string *zname, int f return NULL; } ZVAL_STR(&member, zname); - if (sxe_prop_dim_write(object, &member, NULL, 1, 0, &node) == &EG(error_zval)) { + if (sxe_prop_dim_write(object, &member, NULL, SXE_ACCESS_ELEMENTS, &node) == &EG(error_zval)) { return &EG(error_zval); } type = SXE_ITER_NONE; @@ -668,7 +660,7 @@ static zval *sxe_property_get_adr(zend_object *object, zend_string *zname, int f /* }}} */ /* {{{ sxe_prop_dim_exists() */ -static int sxe_prop_dim_exists(zend_object *object, zval *member, int check_empty, bool elements, bool attribs) +static int sxe_prop_dim_exists(zend_object *object, zval *member, int check_empty, sxe_access_mode access_mode) { php_sxe_object *sxe; xmlNodePtr node; @@ -692,8 +684,7 @@ static int sxe_prop_dim_exists(zend_object *object, zval *member, int check_empt if (Z_TYPE_P(member) == IS_LONG) { if (sxe->iter.type != SXE_ITER_ATTRLIST) { - attribs = 0; - elements = 1; + access_mode = SXE_ACCESS_ELEMENTS; if (sxe->iter.type == SXE_ITER_CHILD) { node = php_sxe_get_first_node_non_destructive(sxe, node); } @@ -701,8 +692,7 @@ static int sxe_prop_dim_exists(zend_object *object, zval *member, int check_empt } if (sxe->iter.type == SXE_ITER_ATTRLIST) { - attribs = 1; - elements = 0; + access_mode = SXE_ACCESS_ATTRIBS; node = php_sxe_get_first_node_non_destructive(sxe, node); attr = (xmlAttrPtr)node; test = sxe->iter.name != NULL; @@ -713,7 +703,7 @@ static int sxe_prop_dim_exists(zend_object *object, zval *member, int check_empt } if (node) { - if (attribs) { + if (access_mode == SXE_ACCESS_ATTRIBS) { if (Z_TYPE_P(member) == IS_LONG) { int nodendx = 0; @@ -742,9 +732,7 @@ static int sxe_prop_dim_exists(zend_object *object, zval *member, int check_empt /* Attribute with no content in its text node */ exists = 0; } - } - - if (elements) { + } else { if (Z_TYPE_P(member) == IS_LONG) { if (sxe->iter.type == SXE_ITER_CHILD) { node = php_sxe_get_first_node_non_destructive(sxe, node); @@ -777,19 +765,19 @@ static int sxe_property_exists(zend_object *object, zend_string *name, int check { zval member; ZVAL_STR(&member, name); - return sxe_prop_dim_exists(object, &member, check_empty, 1, 0); + return sxe_prop_dim_exists(object, &member, check_empty, SXE_ACCESS_ELEMENTS); } /* }}} */ /* {{{ sxe_dimension_exists() */ static int sxe_dimension_exists(zend_object *object, zval *member, int check_empty) { - return sxe_prop_dim_exists(object, member, check_empty, 0, 1); + return sxe_prop_dim_exists(object, member, check_empty, SXE_ACCESS_ATTRIBS); } /* }}} */ /* {{{ sxe_prop_dim_delete() */ -static void sxe_prop_dim_delete(zend_object *object, zval *member, bool elements, bool attribs) +static void sxe_prop_dim_delete(zend_object *object, zval *member, sxe_access_mode access_mode) { php_sxe_object *sxe; xmlNodePtr node; @@ -814,8 +802,7 @@ static void sxe_prop_dim_delete(zend_object *object, zval *member, bool elements if (Z_TYPE_P(member) == IS_LONG) { if (sxe->iter.type != SXE_ITER_ATTRLIST) { - attribs = 0; - elements = 1; + access_mode = SXE_ACCESS_ELEMENTS; if (sxe->iter.type == SXE_ITER_CHILD) { node = php_sxe_get_first_node_non_destructive(sxe, node); } @@ -823,8 +810,7 @@ static void sxe_prop_dim_delete(zend_object *object, zval *member, bool elements } if (sxe->iter.type == SXE_ITER_ATTRLIST) { - attribs = 1; - elements = 0; + access_mode = SXE_ACCESS_ATTRIBS; node = php_sxe_get_first_node_non_destructive(sxe, node); attr = (xmlAttrPtr)node; test = sxe->iter.name != NULL; @@ -837,7 +823,7 @@ static void sxe_prop_dim_delete(zend_object *object, zval *member, bool elements if (node) { php_libxml_invalidate_node_list_cache_from_doc(node->doc); - if (attribs) { + if (access_mode == SXE_ACCESS_ATTRIBS) { if (Z_TYPE_P(member) == IS_LONG) { int nodendx = 0; @@ -861,9 +847,7 @@ static void sxe_prop_dim_delete(zend_object *object, zval *member, bool elements attr = anext; } } - } - - if (elements) { + } else { if (Z_TYPE_P(member) == IS_LONG) { if (sxe->iter.type == SXE_ITER_CHILD) { node = php_sxe_get_first_node_non_destructive(sxe, node); @@ -901,14 +885,14 @@ static void sxe_property_delete(zend_object *object, zend_string *name, void **c { zval member; ZVAL_STR(&member, name); - sxe_prop_dim_delete(object, &member, 1, 0); + sxe_prop_dim_delete(object, &member, SXE_ACCESS_ELEMENTS); } /* }}} */ /* {{{ sxe_dimension_unset() */ static void sxe_dimension_delete(zend_object *object, zval *offset) { - sxe_prop_dim_delete(object, offset, 0, 1); + sxe_prop_dim_delete(object, offset, SXE_ACCESS_ATTRIBS); } /* }}} */ @@ -951,29 +935,22 @@ static void get_base_node_value(php_sxe_object *sxe_ref, xmlNodePtr node, zval * php_libxml_increment_node_ptr((php_libxml_node_object *)subnode, node, NULL); ZVAL_OBJ(value, &subnode->zo); - /*zval_add_ref(value);*/ } } /* }}} */ static void sxe_properties_add(HashTable *rv, char *name, int namelen, zval *value) /* {{{ */ { - zend_string *key; - zval *data_ptr; - zval newptr; - - key = zend_string_init(name, namelen, 0); - if ((data_ptr = zend_hash_find(rv, key)) != NULL) { + zend_string *key = zend_string_init(name, namelen, 0); + zval *data_ptr = zend_hash_lookup(rv, key); + if (!Z_ISNULL_P(data_ptr)) { if (Z_TYPE_P(data_ptr) == IS_ARRAY) { zend_hash_next_index_insert_new(Z_ARRVAL_P(data_ptr), value); } else { - array_init(&newptr); - zend_hash_next_index_insert_new(Z_ARRVAL(newptr), data_ptr); - zend_hash_next_index_insert_new(Z_ARRVAL(newptr), value); - ZVAL_ARR(data_ptr, Z_ARR(newptr)); + ZVAL_ARR(data_ptr, zend_new_pair(data_ptr, value)); } } else { - zend_hash_add_new(rv, key, value); + ZVAL_COPY_VALUE(data_ptr, value); } zend_string_release_ex(key, 0); } @@ -1663,10 +1640,11 @@ PHP_METHOD(SimpleXMLElement, addChild) { php_sxe_object *sxe; char *qname, *value = NULL, *nsuri = NULL; - size_t qname_len, value_len = 0, nsuri_len = 0; + size_t qname_len, value_len = 0, nsuri_len = 0; xmlNodePtr node, newnode; xmlNsPtr nsptr = NULL; xmlChar *localname, *prefix = NULL; + bool free_localname = false; if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s!s!", &qname, &qname_len, &value, &value_len, &nsuri, &nsuri_len) == FAILURE) { @@ -1697,7 +1675,9 @@ PHP_METHOD(SimpleXMLElement, addChild) localname = xmlSplitQName2((xmlChar *)qname, &prefix); if (localname == NULL) { - localname = xmlStrdup((xmlChar *)qname); + localname = (xmlChar *)qname; + } else { + free_localname = true; } newnode = xmlNewChild(node, NULL, localname, (xmlChar *)value); @@ -1717,7 +1697,9 @@ PHP_METHOD(SimpleXMLElement, addChild) node_as_zval_str(sxe, newnode, return_value, SXE_ITER_NONE, localname, prefix, 0); - xmlFree(localname); + if (free_localname) { + xmlFree(localname); + } if (prefix != NULL) { xmlFree(prefix); } @@ -2018,7 +2000,7 @@ PHP_METHOD(SimpleXMLElement, key) RETURN_THROWS(); } - curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->node)->node; + curnode = intern->node->node; RETURN_STRINGL((char*)curnode->name, xmlStrlen(curnode->name)); } /* }}} */ @@ -2509,7 +2491,7 @@ static void php_sxe_iterator_current_key(zend_object_iterator *iter, zval *key) xmlNodePtr curnode = NULL; if (intern != NULL && intern->node != NULL) { - curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->node)->node; + curnode = intern->node->node; } if (curnode) {