diff options
Diffstat (limited to 'ext/domxml/php_domxml.c')
| -rw-r--r-- | ext/domxml/php_domxml.c | 269 | 
1 files changed, 192 insertions, 77 deletions
diff --git a/ext/domxml/php_domxml.c b/ext/domxml/php_domxml.c index e665c15fb9..a133e82d43 100644 --- a/ext/domxml/php_domxml.c +++ b/ext/domxml/php_domxml.c @@ -317,6 +317,7 @@ static function_entry php_domxmldoc_class_functions[] = {  	PHP_FALIAS(create_document_fragment,	domxml_doc_create_document_fragment,	NULL)  	PHP_FALIAS(get_elements_by_tagname,	domxml_doc_get_elements_by_tagname,	NULL)  	PHP_FALIAS(get_element_by_id,		domxml_doc_get_element_by_id,	NULL) +	PHP_FALIAS(free,					domxml_doc_free_doc,			NULL)  	/* Everything below this comment is none DOM compliant */  	/* children is deprecated because it is inherited from DomNode */  /*	PHP_FALIAS(children,				domxml_node_children,			NULL) */ @@ -537,9 +538,9 @@ zend_module_entry domxml_module_entry = {  	"domxml",  	domxml_functions,  	PHP_MINIT(domxml), +	PHP_MSHUTDOWN(domxml),  	NULL, -	PHP_RINIT(domxml), -	NULL, +	NULL(domxml),  	PHP_MINFO(domxml),  	DOMXML_API_VERSION, /* Extension versionnumber */  	STANDARD_MODULE_PROPERTIES @@ -597,28 +598,105 @@ static inline void node_wrapper_dtor(xmlNodePtr node)  } + +/*	This function should only be used when freeing nodes  +	as dependant objects are destroyed */ +static inline void node_wrapper_free(xmlNodePtr node) +{ +	zval *wrapper, **handle; +	int type, refcount = 0; + +	if (!node) { +		return; +	} + +	wrapper = dom_object_get_data(node); +	if (wrapper != NULL ) { +		/* All references need to be destroyed */ +		if (zend_hash_index_find(Z_OBJPROP_P(wrapper), 0, (void **) &handle) ==	SUCCESS) { +			TSRMLS_FETCH(); +			if (zend_list_find(Z_LVAL_PP(handle), &type)) { +				zend_list_delete(Z_LVAL_PP(handle)); +			} +		} else { +			refcount = wrapper->refcount; +			zval_ptr_dtor(&wrapper); + +			/* only set it to null, if refcount was 1 before, otherwise it has still needed references */ +			if (refcount == 1) { +				dom_object_set_data(node, NULL); +			} +		} +	} + +} +  static inline void attr_list_wrapper_dtor(xmlAttrPtr attr)  {  	while (attr != NULL) { +		/* Attribute nodes contain children which can be accessed */  		node_wrapper_dtor((xmlNodePtr) attr);  		attr = attr->next;  	}  } -static inline void node_list_wrapper_dtor(xmlNodePtr node) +/*	destroyref is a bool indicating if all registered objects for nodes  +	within the tree should be destroyed */ +static inline void node_list_wrapper_dtor(xmlNodePtr node, int destroyref)  {  	while (node != NULL) { -		node_list_wrapper_dtor(node->children); +		node_list_wrapper_dtor(node->children, destroyref);  		switch (node->type) {  			/* Skip property freeing for the following types */  			case XML_ATTRIBUTE_DECL:  			case XML_DTD_NODE:  			case XML_ENTITY_DECL: +			case XML_ATTRIBUTE_NODE:  				break;  			default: -				attr_list_wrapper_dtor(node->properties); +				/*	Attribute Nodes contain accessible children +					Call this function with the propert list +				attr_list_wrapper_dtor(node->properties);  */ +				node_list_wrapper_dtor((xmlNodePtr) node->properties, destroyref);  		} -		node_wrapper_dtor(node); + +		if (destroyref == 1) { +			node_wrapper_free(node); +		} else { +			node_wrapper_dtor(node); +		} + +		node = node->next; +	} +} + +/*	Navigate through the tree and unlink nodes which are referenced by objects */ +static inline void node_list_unlink(xmlNodePtr node) +{ +	zval *wrapper; + +	while (node != NULL) { + +		wrapper = dom_object_get_data(node); + +		if (wrapper != NULL ) { +			/* This node is referenced so no need to check children */ +			xmlUnlinkNode(node); +		} else { +			node_list_unlink(node->children); + +			switch (node->type) { +				/* Skip property freeing for the following types */ +				case XML_ATTRIBUTE_DECL: +				case XML_DTD_NODE: +				case XML_ENTITY_DECL: +				case XML_ATTRIBUTE_NODE: +					break; +				default: +					node_list_unlink((xmlNodePtr) node->properties); +			} +		} +  		node = node->next;  	}  } @@ -651,7 +729,7 @@ static void php_free_xml_doc(zend_rsrc_list_entry *rsrc TSRMLS_DC)  	xmlDoc *doc = (xmlDoc *) rsrc->ptr;  	if (doc) { -		node_list_wrapper_dtor(doc->children); +		node_list_wrapper_dtor(doc->children, 0);  		node_wrapper_dtor((xmlNodePtr) doc);  		xmlFreeDoc(doc);  	} @@ -664,8 +742,10 @@ static void php_free_xml_node(zend_rsrc_list_entry *rsrc TSRMLS_DC)  	/* if node has no parent, it will not be freed by php_free_xml_doc, so do it here  	and for all children as well. */  	if (node->parent == NULL) { -		attr_list_wrapper_dtor(node->properties); -		node_list_wrapper_dtor(node->children); +		/* Attribute Nodes ccontain accessible children  +		attr_list_wrapper_dtor(node->properties); */ +		node_list_wrapper_dtor((xmlNodePtr) node->properties, 0); +		node_list_wrapper_dtor(node->children, 0);  		node_wrapper_dtor(node);  		xmlFreeNode(node);  	} else { @@ -711,43 +791,37 @@ static void php_free_xml_parser(zend_rsrc_list_entry *rsrc TSRMLS_DC)  #if HAVE_DOMXSLT -static void php_free_xslt_stylesheet(zend_rsrc_list_entry *rsrc TSRMLS_DC) -{ -	xsltStylesheetPtr sheet = (xsltStylesheetPtr) rsrc->ptr; - -	if (sheet) { -		node_wrapper_dtor((xmlNodePtr) sheet); -		xsltFreeStylesheet(sheet); -	} -} -  static void xsltstylesheet_set_data(void *obj, zval *wrapper)  { -/* -	char tmp[20]; -	sprintf(tmp, "%08X", obj); -	fprintf(stderr, "Adding %s to hash\n", tmp); -*/  	((xsltStylesheetPtr) obj)->_private = wrapper;  } - -#ifdef HELLY_0  static zval *xsltstylesheet_get_data(void *obj)  { -/* -	char tmp[20]; -	sprintf(tmp, "%08X", obj); -	fprintf(stderr, "Trying getting %s from object ...", tmp); -	if (((xmlNodePtr) obj)->_private) { -		fprintf(stderr, " found\n"); -	} else { -		fprintf(stderr, " not found\n"); -	} -*/  	return ((zval *) (((xsltStylesheetPtr) obj)->_private));  } -#endif + +static void php_free_xslt_stylesheet(zend_rsrc_list_entry *rsrc TSRMLS_DC) +{ +	xsltStylesheetPtr sheet = (xsltStylesheetPtr) rsrc->ptr; +	zval *wrapper; +	int refcount = 0; + +	if (sheet) { +		wrapper = xsltstylesheet_get_data(sheet); + +		if (wrapper != NULL ) { +			refcount = wrapper->refcount; +			zval_ptr_dtor(&wrapper); + +			/* only set it to null, if refcount was 1 before, otherwise it has still needed references */ +			if (refcount == 1) { +				xsltstylesheet_set_data(sheet, NULL); +			} +		} +		xsltFreeStylesheet(sheet); +	} +}  void *php_xsltstylesheet_get_object(zval *wrapper, int rsrc_type1, int rsrc_type2 TSRMLS_DC)  { @@ -1484,21 +1558,29 @@ xmlDocPtr php_dom_xmlSAXParse(xmlSAXHandlerPtr sax, const char *buffer, int size  	return(ret);  } -PHP_RINIT_FUNCTION(domxml) +PHP_MSHUTDOWN_FUNCTION(domxml)  { +#if HAVE_DOMXSLT +	xsltCleanupGlobals(); +#endif +   	xmlCleanupParser(); +	 +/*	If you want do find memleaks in this module, compile libxml2 with --with-mem-debug and +	uncomment the following line, this will tell you the amount of not freed memory +	and the total used memory into apaches error_log  */ +/*  xmlMemoryDump();*/ +  	return SUCCESS;  } -/* PHP_MINIT_FUNCTION(domxml) - */  PHP_MINIT_FUNCTION(domxml)  {  	zend_class_entry ce;  	le_domxmlnodep = zend_register_list_destructors_ex(php_free_xml_node, NULL, "domnode", module_number);  	le_domxmlcommentp = zend_register_list_destructors_ex(php_free_xml_node, NULL, "domcomment", module_number); -	le_domxmlattrp = zend_register_list_destructors_ex(php_free_xml_attr, NULL, "domattribute", module_number);  	le_domxmltextp = zend_register_list_destructors_ex(php_free_xml_node, NULL, "domtext", module_number); +	le_domxmlattrp = zend_register_list_destructors_ex(php_free_xml_attr, NULL, "domattribute", module_number);  	le_domxmlelementp =	zend_register_list_destructors_ex(php_free_xml_node, NULL, "domelement", module_number);  	le_domxmldtdp = zend_register_list_destructors_ex(php_free_xml_node, NULL, "domdtd", module_number);  	le_domxmlcdatap = zend_register_list_destructors_ex(php_free_xml_node, NULL, "domcdata", module_number); @@ -2839,6 +2921,13 @@ PHP_FUNCTION(domxml_elem_set_attribute)  	DOMXML_PARAM_FOUR(nodep, id, le_domxmlelementp, "ss", &name, &name_len, &value, &value_len); + +	/*	If attribute exists, all children nodes are freed by setprop  +		unlink referenced children */ +	attr = xmlHasProp(nodep,name); +	if (attr != NULL) { +		node_list_unlink(attr->children); +	}  	attr = xmlSetProp(nodep, name, value);  	if (!attr) {  		php_error_docref(NULL TSRMLS_CC, E_WARNING, "No such attribute '%s'", name); @@ -2864,7 +2953,17 @@ PHP_FUNCTION(domxml_elem_remove_attribute)  	if (attrp == NULL) {  		RETURN_FALSE;  	} -	xmlUnlinkNode((xmlNodePtr)attrp); + +	/*	Check for registered nodes within attributes tree when attribute is not referenced   +		Unlink dependant nodes and free attribute if not registered */ +	if (dom_object_get_data((xmlNodePtr) attrp) == NULL) { +		node_list_unlink(attrp->children); +		xmlUnlinkNode((xmlNodePtr) attrp); +		xmlFreeProp(attrp); +	} else { +		xmlUnlinkNode((xmlNodePtr) attrp); +	} +  	RETURN_TRUE;  }  /* }}} */ @@ -2910,47 +3009,36 @@ PHP_FUNCTION(domxml_elem_set_attribute_node)  		RETURN_FALSE;  	} -  	existattrp = xmlHasProp(nodep,attrp->name);  	if (existattrp != NULL) { -		/* We cannot unlink an existing attribute as it may never be freed -		Only the content of the text node of an attribute node is transfered over */ - -		xmlChar *mem; -		xmlNode *first, *firstattrp; - -		first = existattrp->children; -		firstattrp = attrp->children; -		if (mem = xmlNodeGetContent(firstattrp)) { -			if (!first) { -				xmlNodeSetContent((xmlNode *) existattrp, mem); -			} else { -				xmlNodeSetContent(first, mem); -			} -			xmlFree(mem); -			newattrp = existattrp; +		/*	Check for registered nodes within attributes tree when attribute is not referenced  +			Unlink dependant nodes and free attribute if not registered */ +		if (dom_object_get_data((xmlNodePtr) existattrp) == NULL) { +			node_list_unlink(existattrp->children); +			xmlUnlinkNode((xmlNodePtr) existattrp); +			xmlFreeProp(existattrp);  		} else { -			RETURN_FALSE; +			xmlUnlinkNode((xmlNodePtr) existattrp);  		} +	} + +	/* xmlCopyProp does not add the copy to the element node. +		It does set the parent of the copy to the element node however */ +	newattrp = xmlCopyProp(nodep, attrp); +	if (!newattrp) { +		php_error_docref(NULL TSRMLS_CC, E_WARNING, "No such attribute '%s'", attrp->name); +		RETURN_FALSE;  	} else { -		/* xmlCopyProp does not add the copy to the element node. -			It does set the parent of the copy to the element node however */ -		newattrp = xmlCopyProp(nodep, attrp); -		if (!newattrp) { -			php_error_docref(NULL TSRMLS_CC, E_WARNING, "No such attribute '%s'", attrp->name); -			RETURN_FALSE; +		xmlAttr *prop; +		prop = nodep->properties; +		if (prop == NULL) { +			nodep->properties = newattrp;  		} else { -			xmlAttr *prop; -			prop = nodep->properties; -			if (prop == NULL) { -				nodep->properties = newattrp; -			} else { -				while (prop->next != NULL) { -					prop = prop->next; -				} -				prop->next = newattrp; -				newattrp->prev = prop; +			while (prop->next != NULL) { +				prop = prop->next;  			} +			prop->next = newattrp; +			newattrp->prev = prop;  		}  	} @@ -4319,6 +4407,30 @@ PHP_FUNCTION(domxml_new_xmldoc)  }  /* }}} */ +/* {{{ proto bool domxml_doc_free_doc() +   Frees xmldoc and removed objects from hash */ +PHP_FUNCTION(domxml_doc_free_doc) +{ +	zval *doc; +	xmlNode *docp; + +	DOMXML_GET_THIS_OBJ(docp, doc, le_domxmldocp); + +	if (docp->type != XML_DOCUMENT_NODE) { +		php_error_docref(NULL TSRMLS_CC, E_WARNING, "DOM Document is required"); +		RETURN_FALSE; +	} + +	node_list_wrapper_dtor(docp->children, 1); +	node_list_wrapper_dtor((xmlNodePtr) docp->properties, 1); +	/* Attribute Nodes ccontain accessible children  +	attr_list_wrapper_dtor(docp->properties); */ +	node_wrapper_free(docp); + +	RETURN_TRUE; +} +/* }}} */ +  /* {{{ proto object domxml_parser([string buf[,string filename]])     Creates new xmlparser */  PHP_FUNCTION(domxml_parser) @@ -4694,6 +4806,7 @@ static int node_attributes(zval **attributes, xmlNode *nodep TSRMLS_DC)  	while (attr) {  		zval *pattr;  		int ret; +		xmlChar *content;  		pattr = php_domobject_new((xmlNodePtr) attr, &ret, NULL TSRMLS_CC);  		/** XXX FIXME XXX */ @@ -4701,7 +4814,9 @@ static int node_attributes(zval **attributes, xmlNode *nodep TSRMLS_DC)  			zend_hash_update(Z_OBJPROP_P(value), "children", sizeof("children"), (void *) &children, sizeof(zval *), NULL);  		}  */		add_property_string(pattr, "name", (char *) (attr->name), 1); -		add_property_string(pattr, "value", xmlNodeGetContent((xmlNodePtr) attr), 1); +		content = xmlNodeGetContent((xmlNodePtr) attr); +		add_property_string(pattr, "value", content, 1); +		xmlFree(content);  		zend_hash_next_index_insert(Z_ARRVAL_PP(attributes), &pattr, sizeof(zval *), NULL);  		attr = attr->next;  		count++;  | 
