From: Sterling Hughes Date: Tue, 27 May 2003 18:41:02 +0000 (+0000) Subject: plane hacking X-Git-Tag: RELEASE_1_0_2~566 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c60879dbb92fde970a95598fc1b860a1cda75f46;p=php plane hacking --- diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c index 7634107354..466c38b7fb 100644 --- a/ext/simplexml/simplexml.c +++ b/ext/simplexml/simplexml.c @@ -29,6 +29,11 @@ zend_class_entry *sxe_class_entry; +#define SKIP_TEXT(__p) \ + if ((__p)->type == XML_TEXT_NODE) { \ + goto next_iter; \ + } + static php_sxe_object *php_sxe_object_new(TSRMLS_D); static zend_object_value php_sxe_register_object(php_sxe_object * TSRMLS_DC); @@ -99,7 +104,7 @@ sxe_property_read(zval *object, zval *member TSRMLS_DC) APPEND_PREV_ELEMENT(counter, value); MAKE_STD_ZVAL(value); - contents = xmlNodeListGetString(sxe->document, attr->xmlChildrenNode, 1); + contents = xmlNodeListGetString(sxe->document, attr->children, 1); ZVAL_STRING(value, contents, 0); APPEND_CUR_ELEMENT(counter, value); @@ -110,9 +115,11 @@ sxe_property_read(zval *object, zval *member TSRMLS_DC) if (!sxe->node) { sxe->node = node; } - node = node->xmlChildrenNode; + node = node->children; while (node) { + SKIP_TEXT(node); + if (node->ns && !xmlStrcmp(node->ns->prefix, name)) { APPEND_PREV_ELEMENT(counter, value); @@ -129,6 +136,7 @@ sxe_property_read(zval *object, zval *member TSRMLS_DC) APPEND_CUR_ELEMENT(counter, value); } +next_iter: node = node->next; } @@ -192,21 +200,23 @@ sxe_property_write(zval *object, zval *member, zval *value TSRMLS_DC) attr = attr->next; } - node = node->xmlChildrenNode; + node = node->children; while (node) { + SKIP_TEXT(node); if (!xmlStrcmp(node->name, name)) { newnode = node; ++counter; } +next_iter: node = node->next; } if (counter == 1) { if (is_attr) { - change_node_zval(attr->xmlChildrenNode, value); + change_node_zval(attr->children, value); } else { - change_node_zval(newnode->xmlChildrenNode, value); + change_node_zval(newnode->children, value); } } else if (counter > 1) { php_error(E_WARNING, "Cannot assign to an array of nodes (duplicate subnodes or attr detected)\n"); @@ -258,12 +268,15 @@ sxe_property_exists(zval *object, zval *member, int check_empty TSRMLS_DC) attr = attr->next; } - node = node->xmlChildrenNode; + node = node->children; while (node) { + SKIP_TEXT(node); + if (!xmlStrcmp(node->name, name)) { return 1; } +next_iter: node = node->next; } @@ -276,7 +289,66 @@ sxe_property_exists(zval *object, zval *member, int check_empty TSRMLS_DC) static void sxe_property_delete(zval *object, zval *member TSRMLS_DC) { + php_sxe_object *sxe; + xmlNodePtr node; + xmlNodePtr nnext; + xmlAttrPtr attr; + xmlAttrPtr anext; + + sxe = php_sxe_fetch_object(object TSRMLS_CC); + + GET_NODE(sxe, node); + + attr = node->properties; + while (attr) { + anext = attr->next; + if (!xmlStrcmp(attr->name, Z_STRVAL_P(member))) { + // free + } + attr = anext; + } + + node = node->children; + while (node) { + nnext = node->next; + + SKIP_TEXT(node); + + if (!xmlStrcmp(node->name, Z_STRVAL_P(member))) { + xmlUnlinkNode(node); + xmlFreeNode(node); + } + +next_iter: + node = nnext; + } +} +/* }}} */ + +/* {{{ _get_base_node_value() + */ +static void +_get_base_node_value(xmlNodePtr node, zval **value TSRMLS_CC) +{ + php_sxe_object *subnode; + char *contents; + + MAKE_STD_ZVAL(*value); + if (node->children && node->children->type == XML_TEXT_NODE && !xmlIsBlankNode(node->children)) { + contents = xmlNodeListGetString(node->doc, node->children, 1); + if (contents) { + ZVAL_STRING(*value, contents, 1); + } + } else { + subnode = php_sxe_object_new(TSRMLS_C); + subnode->document = node->doc; + subnode->node = node; + + (*value)->type = IS_OBJECT; + (*value)->value.obj = php_sxe_register_object(subnode TSRMLS_CC); + zval_add_ref(value); + } } /* }}} */ @@ -285,10 +357,15 @@ sxe_property_delete(zval *object, zval *member TSRMLS_DC) static HashTable * sxe_properties_get(zval *object TSRMLS_DC) { - HashTable *rv; - php_sxe_object *sxe; - xmlNodePtr node; - int counter = 0; + zval **data_ptr; + zval *value; + zval *newptr; + HashTable *rv; + php_sxe_object *sxe; + char *name; + xmlNodePtr node; + ulong h; + int namelen; ALLOC_HASHTABLE_REL(rv); zend_hash_init(rv, 0, NULL, ZVAL_PTR_DTOR, 0); @@ -296,14 +373,37 @@ sxe_properties_get(zval *object TSRMLS_DC) sxe = php_sxe_fetch_object(object TSRMLS_CC); GET_NODE(sxe, node); + node = node->children; + + while (node) { + SKIP_TEXT(node); + + _get_base_node_value(node, &value TSRMLS_CC); + + name = (char *) node->name; + namelen = xmlStrlen(node->name) + 1; + + h = zend_hash_func(name, namelen); + if (zend_hash_quick_find(rv, name, namelen, h, (void **) &data_ptr) == SUCCESS) { + if (Z_TYPE_PP(data_ptr) == IS_ARRAY) { + zend_hash_next_index_insert(Z_ARRVAL_PP(data_ptr), &value, sizeof(zval *), NULL); + } else { + MAKE_STD_ZVAL(newptr); + array_init(newptr); + + zend_hash_next_index_insert(Z_ARRVAL_P(newptr), data_ptr, sizeof(zval *), NULL); + zend_hash_next_index_insert(Z_ARRVAL_P(newptr), &value, sizeof(zval *), NULL); + + zend_hash_quick_update(rv, name, namelen, h, &newptr, sizeof(zval *), NULL); + } + } else { + zend_hash_quick_update(rv, name, namelen, h, &value, sizeof(zval *), NULL); + } + +next_iter: + node = node->next; + } - /* - * XXX: TODO - * Recurse from the current node through the XML document - * and build an array return value. Expensive? sure. But - * if you ask for it, you get it :) - */ - return rv; } /* }}} */ @@ -313,7 +413,21 @@ sxe_properties_get(zval *object TSRMLS_DC) static int sxe_objects_compare(zval *object1, zval *object2 TSRMLS_DC) { - return 0; + php_sxe_object *sxe1; + php_sxe_object *sxe2; + + sxe1 = php_sxe_fetch_object(object1 TSRMLS_CC); + sxe2 = php_sxe_fetch_object(object2 TSRMLS_CC); + + if (sxe1->node == NULL) { + if (sxe2->node) { + return 1; + } else if (sxe1->document == sxe2->document) { + return 9; + } + } else { + return !(sxe1->node == sxe2->node); + } } /* }}} */ @@ -375,7 +489,12 @@ simplexml_ce_xpath_search(INTERNAL_FUNCTION_PARAMETERS) for (i = 0; i < result->nodeNr; ++i) { MAKE_STD_ZVAL(value); - if (!xmlStrcmp(result->nodeTab[i]->name, "text")) { + /** + * Detect the case where the last selector is text(), simplexml + * always accesses the text() child by default, therefore we assign + * to the parent node. + */ + if (result->nodeTab[i]->type == XML_TEXT_NODE) { _node_as_zval(sxe, result->nodeTab[i]->parent, value); } else { _node_as_zval(sxe, result->nodeTab[i], value); @@ -418,43 +537,22 @@ sxe_class_name_get(zval *object, char **class_name, zend_uint *class_name_len, i { *class_name = estrdup("simplexml_element"); *class_name_len = sizeof("simplexml_element"); + return 0; } /* }}} */ -/* {{{ cast_empty_object() +/* {{{ cast_object() */ static inline void -cast_empty_object(zval *object, int type TSRMLS_DC) +cast_object(zval *object, int type, char *contents TSRMLS_DC) { - object->type = IS_NULL; - switch (type) { - case IS_BOOL: - convert_to_boolean(object); - break; - case IS_LONG: - convert_to_long(object); - break; - case IS_DOUBLE: - convert_to_double(object); - break; - case IS_STRING: - convert_to_string(object); - break; + if (contents) { + int len = strlen(contents); + ZVAL_STRINGL(object, contents, len, 1); + } else { + ZVAL_NULL(object); } -} -/* }}} */ - -/* {{{ cast_object_with_contents() - */ -static inline void -cast_object_with_contents(zval *object, int type, char *contents TSRMLS_DC) -{ - int len = strlen(contents); - - object->value.str.val = estrndup(contents, len); - object->value.str.len = len; - object->type = IS_STRING; switch (type) { case IS_STRING: @@ -487,13 +585,13 @@ sxe_object_cast(zval *readobj, zval *writeobj, int type, int should_free TSRMLS_ } if (sxe->node) { - contents = xmlNodeListGetString(sxe->document, sxe->node->xmlChildrenNode, 1); - if (!xmlIsBlankNode(sxe->node->xmlChildrenNode) && contents) { - cast_empty_object(writeobj, type TSRMLS_CC); + contents = xmlNodeListGetString(sxe->document, sxe->node->children, 1); + if (!xmlIsBlankNode(sxe->node->children) && contents) { + cast_object(writeobj, type, NULL TSRMLS_CC); } } - cast_object_with_contents(writeobj, type, contents TSRMLS_CC); + cast_object(writeobj, type, contents TSRMLS_CC); } /* }}} */ @@ -504,7 +602,7 @@ sxe_object_set(zval **property, zval *value TSRMLS_DC) { /* XXX: TODO * This call is not yet implemented in the engine - * so leave them blank for now. + * so leave it blank for now. */ } /* }}} */ @@ -516,7 +614,7 @@ sxe_object_get(zval *property TSRMLS_DC) { /* XXX: TODO * This call is not yet implemented in the engine - * so leave them blank for now. + * so leave it blank for now. */ return NULL; } @@ -545,9 +643,24 @@ static zend_object_handlers sxe_object_handlers[] = { /* {{{ sxe_object_clone() */ static void -sxe_object_clone(void *object, void **clone TSRMLS_DC) +sxe_object_clone(void *object, void **clone_ptr TSRMLS_DC) { - + php_sxe_object *sxe = (php_sxe_object *) object; + php_sxe_object *clone; + + clone = php_sxe_object_new(TSRMLS_C); + + /** + * XXX: Change parts of the code not to rely on sxe->document + * being set. + */ + if (xmlDocGetRootElement(sxe->document) == sxe->node) { + clone->document = xmlCopyDoc(sxe->document, 1); + } else { + clone->node = xmlCopyNode(sxe->node, 0); + } + + *clone_ptr = (void *) clone; } /* }}} */ @@ -556,6 +669,18 @@ sxe_object_clone(void *object, void **clone TSRMLS_DC) static void sxe_object_dtor(void *object, zend_object_handle handle TSRMLS_DC) { + php_sxe_object *sxe; + + sxe = (php_sxe_object *) object; + + if (sxe->document) { + xmlFreeDoc(sxe->document); + } + + if (sxe->xpath) { + xmlXPathFreeContext(sxe->xpath); + } + zend_objects_destroy_object(object, handle TSRMLS_CC); } /* }}} */