diff options
author | Rob Richards <rrichards@php.net> | 2003-10-26 15:53:20 +0000 |
---|---|---|
committer | Rob Richards <rrichards@php.net> | 2003-10-26 15:53:20 +0000 |
commit | d29fb55bbb6c33aa10861f312176c07dafe61046 (patch) | |
tree | ddd82e4c132b17e9c36a34be31cbbc957bdfd1de /ext | |
parent | 7e906476117df84ae22d498b935ec3531c62ae57 (diff) | |
download | php-git-d29fb55bbb6c33aa10861f312176c07dafe61046.tar.gz |
common functions for interoperability
Diffstat (limited to 'ext')
-rw-r--r-- | ext/libxml/libxml.c | 268 | ||||
-rw-r--r-- | ext/libxml/php_libxml.h | 30 |
2 files changed, 296 insertions, 2 deletions
diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c index 8055c7844b..ada4121b7f 100644 --- a/ext/libxml/libxml.c +++ b/ext/libxml/libxml.c @@ -91,6 +91,131 @@ zend_module_entry libxml_module_entry = { /* }}} */ +/* {{{ internal functions for interoperability */ +static int php_libxml_dec_node(php_libxml_node_ptr *nodeptr) +{ + int ret_refcount; + + ret_refcount = --nodeptr->refcount; + if (ret_refcount == 0) { + if (nodeptr->node != NULL && nodeptr->node->type != XML_DOCUMENT_NODE) { + nodeptr->node->_private = NULL; + } + /* node is destroyed by another object. reset ret_refcount to 1 and node to NULL + so the php_libxml_node_ptr is detroyed when the object is destroyed */ + nodeptr->refcount = 1; + nodeptr->node = NULL; + } + + return ret_refcount; +} + +static int php_libxml_clear_object(php_libxml_node_object *object TSRMLS_DC) +{ + if (object->properties) { + object->properties = NULL; + } + php_libxml_decrement_node_ptr(object TSRMLS_CC); + return php_libxml_decrement_doc_ref(object TSRMLS_CC); +} + +static int php_libxml_unregister_node(xmlNodePtr nodep TSRMLS_DC) +{ + php_libxml_node_object *wrapper; + + php_libxml_node_ptr *nodeptr = nodep->_private; + + if (nodeptr != NULL) { + wrapper = nodeptr->_private; + if (wrapper) { + php_libxml_clear_object(wrapper TSRMLS_CC); + } else { + php_libxml_dec_node(nodeptr); + } + } + + return -1; +} + +static void php_libxml_node_free(xmlNodePtr node) +{ + if(node) { + if (node->_private != NULL) { + ((php_libxml_node_ptr *) node->_private)->node = NULL; + } + switch (node->type) { + case XML_ATTRIBUTE_NODE: + xmlFreeProp((xmlAttrPtr) node); + break; + case XML_ENTITY_DECL: + case XML_ELEMENT_DECL: + case XML_ATTRIBUTE_DECL: + break; + case XML_NOTATION_NODE: + /* These require special handling */ + if (node->name != NULL) { + xmlFree((char *) node->name); + } + if (((xmlEntityPtr) node)->ExternalID != NULL) { + xmlFree((char *) ((xmlEntityPtr) node)->ExternalID); + } + if (((xmlEntityPtr) node)->SystemID != NULL) { + xmlFree((char *) ((xmlEntityPtr) node)->SystemID); + } + xmlFree(node); + break; + case XML_NAMESPACE_DECL: + if (node->ns) { + xmlFreeNs(node->ns); + node->ns = NULL; + } + node->type = XML_ELEMENT_NODE; + default: + xmlFreeNode(node); + } + } +} + +static void php_libxml_node_free_list(xmlNodePtr node TSRMLS_DC) +{ + xmlNodePtr curnode; + + if (node != NULL) { + curnode = node; + while (curnode != NULL) { + node = curnode; + switch (node->type) { + /* Skip property freeing for the following types */ + case XML_NOTATION_NODE: + break; + case XML_ENTITY_REF_NODE: + php_libxml_node_free_list((xmlNodePtr) node->properties TSRMLS_CC); + break; + case XML_ATTRIBUTE_DECL: + case XML_DTD_NODE: + case XML_DOCUMENT_TYPE_NODE: + case XML_ENTITY_DECL: + case XML_ATTRIBUTE_NODE: + case XML_NAMESPACE_DECL: + php_libxml_node_free_list(node->children TSRMLS_CC); + break; + default: + php_libxml_node_free_list(node->children TSRMLS_CC); + php_libxml_node_free_list((xmlNodePtr) node->properties TSRMLS_CC); + } + + curnode = node->next; + xmlUnlinkNode(node); + if (php_libxml_unregister_node(node TSRMLS_CC) == 0) { + node->doc = NULL; + } + php_libxml_node_free(node); + } + } +} + +/* }}} */ + /* {{{ startup, shutdown and info functions */ #ifdef ZTS static void php_libxml_init_globals(php_libxml_globals *libxml_globals_p TSRMLS_DC) @@ -276,6 +401,149 @@ PHP_FUNCTION(libxml_set_streams_context) } /* }}} */ +/* {{{ Common functions shared by extensions */ +int php_libxml_increment_node_ptr(php_libxml_node_object *object, xmlNodePtr node, void *private_data TSRMLS_DC) +{ + int ret_refcount = -1; + + if (object != NULL && node != NULL) { + if (object->node != NULL) { + if (object->node->node == node) { + return object->node->refcount; + } else { + php_libxml_decrement_node_ptr(object TSRMLS_CC); + } + } + if (node->_private != NULL) { + object->node = node->_private; + ret_refcount = ++object->node->refcount; + /* Only dom uses _private */ + if (object->node->_private == NULL) { + object->node->_private = private_data; + } + } else { + ret_refcount = 1; + object->node = emalloc(sizeof(php_libxml_node_ptr)); + object->node->node = node; + object->node->refcount = 1; + object->node->_private = private_data; + node->_private = object->node; + } + } + + return ret_refcount; +} + +int php_libxml_decrement_node_ptr(php_libxml_node_object *object TSRMLS_DC) { + int ret_refcount = -1; + php_libxml_node_ptr *obj_node; + + if (object != NULL && object->node != NULL) { + obj_node = (php_libxml_node_ptr *) object->node; + ret_refcount = --obj_node->refcount; + if (ret_refcount == 0) { + if (obj_node->node != NULL && obj_node->node->type != XML_DOCUMENT_NODE) { + obj_node->node->_private = NULL; + } + efree(obj_node); + } + object->node = NULL; + } + + return ret_refcount; +} + +int php_libxml_increment_doc_ref(php_libxml_node_object *object, xmlDocPtr docp TSRMLS_DC) { + int ret_refcount = -1; + + if (object->document != NULL) { + object->document->refcount++; + ret_refcount = object->document->refcount; + } else if (docp != NULL) { + ret_refcount = 1; + object->document = emalloc(sizeof(php_libxml_ref_obj)); + object->document->ptr = docp; + object->document->refcount = ret_refcount; + object->document->doc_props = NULL; + } + + return ret_refcount; +} + +int php_libxml_decrement_doc_ref(php_libxml_node_object *object TSRMLS_DC) { + int ret_refcount = -1; + + if (object != NULL && object->document != NULL) { + ret_refcount = --object->document->refcount; + if (ret_refcount == 0) { + if (object->document->ptr != NULL) { + xmlFreeDoc((xmlDoc *) object->document->ptr); + } + if (object->document->doc_props != NULL) { + efree(object->document->doc_props); + } + efree(object->document); + } + object->document = NULL; + } + + return ret_refcount; +} + +void php_libxml_node_free_resource(xmlNodePtr node TSRMLS_DC) +{ + if (!node) { + return; + } + + switch (node->type) { + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + break; + default: + if (node->parent == NULL || node->type == XML_NAMESPACE_DECL) { + php_libxml_node_free_list((xmlNodePtr) node->children TSRMLS_CC); + switch (node->type) { + /* Skip property freeing for the following types */ + case XML_ATTRIBUTE_DECL: + case XML_DTD_NODE: + case XML_DOCUMENT_TYPE_NODE: + case XML_ENTITY_DECL: + case XML_ATTRIBUTE_NODE: + case XML_NAMESPACE_DECL: + break; + default: + php_libxml_node_free_list((xmlNodePtr) node->properties TSRMLS_CC); + } + if (php_libxml_unregister_node(node TSRMLS_CC) == 0) { + node->doc = NULL; + } + php_libxml_node_free(node); + } else { + php_libxml_unregister_node(node TSRMLS_CC); + } + } +} + +void php_libxml_node_decrement_resource(php_libxml_node_object *object TSRMLS_DC) +{ + int ret_refcount = -1; + xmlNodePtr nodep; + php_libxml_node_ptr *obj_node; + + if (object != NULL && object->node != NULL) { + obj_node = (php_libxml_node_ptr *) object->node; + nodep = object->node->node; + ret_refcount = php_libxml_decrement_node_ptr(object TSRMLS_CC); + if (ret_refcount == 0) { + php_libxml_node_free_resource(nodep TSRMLS_CC); + } + /* Safe to call as if the resource were freed then doc pointer is NULL */ + php_libxml_decrement_doc_ref(object TSRMLS_CC); + } +} +/* }}} */ + #endif /* diff --git a/ext/libxml/php_libxml.h b/ext/libxml/php_libxml.h index 9db788496f..6ed39f88ef 100644 --- a/ext/libxml/php_libxml.h +++ b/ext/libxml/php_libxml.h @@ -37,14 +37,40 @@ extern zend_module_entry libxml_module_entry; #define PHP_LIBXML_API #endif - +#include <libxml/tree.h> typedef struct { zval *stream_context; } php_libxml_globals; - +typedef struct _php_libxml_ref_obj { + void *ptr; + int refcount; + void *doc_props; +} php_libxml_ref_obj; + +typedef struct _php_libxml_node_ptr { + xmlNodePtr node; + int refcount; + void *_private; +} php_libxml_node_ptr; + +typedef struct _php_libxml_node_object { + zend_object std; + php_libxml_node_ptr *node; + php_libxml_ref_obj *document; + HashTable *properties; +} php_libxml_node_object; + PHP_FUNCTION(libxml_set_streams_context); +int php_libxml_increment_node_ptr(php_libxml_node_object *object, xmlNodePtr node, void *private_data TSRMLS_DC); +int php_libxml_decrement_node_ptr(php_libxml_node_object *object TSRMLS_DC); +int php_libxml_increment_doc_ref(php_libxml_node_object *object, xmlDocPtr docp TSRMLS_DC); +int php_libxml_decrement_doc_ref(php_libxml_node_object *object TSRMLS_DC); +/* When an explicit freeing of node and children is required */ +void php_libxml_node_free_resource(xmlNodePtr node TSRMLS_DC); +/* When object dtor is called as node may still be referenced */ +void php_libxml_node_decrement_resource(php_libxml_node_object *object TSRMLS_DC); #endif /* HAVE_LIBXML */ |