/* +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2011 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Christian Stocker | | Rob Richards | +----------------------------------------------------------------------+ */ /* $Id$ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php.h" #if HAVE_LIBXML && HAVE_DOM #include "php_dom.h" #include "dom_ce.h" typedef struct _nodeIterator nodeIterator; struct _nodeIterator { int cur; int index; xmlNode *node; }; typedef struct _notationIterator notationIterator; struct _notationIterator { int cur; int index; xmlNotation *notation; }; static void itemHashScanner (void *payload, void *data, xmlChar *name) /* {{{ */ { nodeIterator *priv = (nodeIterator *)data; if(priv->cur < priv->index) { priv->cur++; } else { if(priv->node == NULL) { priv->node = (xmlNode *)payload; } } } /* }}} */ xmlNodePtr create_notation(const xmlChar *name, const xmlChar *ExternalID, const xmlChar *SystemID) /* {{{ */ { xmlEntityPtr ret; ret = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity)); memset(ret, 0, sizeof(xmlEntity)); ret->type = XML_NOTATION_NODE; ret->name = xmlStrdup(name); ret->ExternalID = xmlStrdup(ExternalID); ret->SystemID = xmlStrdup(SystemID); ret->length = 0; ret->content = NULL; ret->URI = NULL; ret->orig = NULL; ret->children = NULL; ret->parent = NULL; ret->doc = NULL; ret->_private = NULL; ret->last = NULL; ret->prev = NULL; return((xmlNodePtr) ret); } /* }}} */ xmlNode *php_dom_libxml_hash_iter(xmlHashTable *ht, int index) /* {{{ */ { xmlNode *nodep = NULL; nodeIterator *iter; int htsize; if ((htsize = xmlHashSize(ht)) > 0 && index < htsize) { iter = emalloc(sizeof(nodeIterator)); iter->cur = 0; iter->index = index; iter->node = NULL; xmlHashScan(ht, itemHashScanner, iter); nodep = iter->node; efree(iter); return nodep; } else { return NULL; } } /* }}} */ xmlNode *php_dom_libxml_notation_iter(xmlHashTable *ht, int index) /* {{{ */ { notationIterator *iter; xmlNotation *notep = NULL; int htsize; if ((htsize = xmlHashSize(ht)) > 0 && index < htsize) { iter = emalloc(sizeof(notationIterator)); iter->cur = 0; iter->index = index; iter->notation = NULL; xmlHashScan(ht, itemHashScanner, iter); notep = iter->notation; efree(iter); return create_notation(notep->name, notep->PublicID, notep->SystemID); } else { return NULL; } } /* }}} */ static void php_dom_iterator_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ { php_dom_iterator *iterator = (php_dom_iterator *)iter; zval_ptr_dtor((zval**)&iterator->intern.data); if (iterator->curobj) { zval_ptr_dtor((zval**)&iterator->curobj); } efree(iterator); } /* }}} */ static int php_dom_iterator_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ { php_dom_iterator *iterator = (php_dom_iterator *)iter; if (iterator->curobj) { return SUCCESS; } else { return FAILURE; } } /* }}} */ static void php_dom_iterator_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */ { php_dom_iterator *iterator = (php_dom_iterator *)iter; *data = &iterator->curobj; } /* }}} */ static int php_dom_iterator_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */ { zval *curobj; xmlNodePtr curnode = NULL; dom_object *intern; zval *object; int namelen; php_dom_iterator *iterator = (php_dom_iterator *)iter; object = (zval *)iterator->intern.data; if (instanceof_function(Z_OBJCE_P(object), dom_nodelist_class_entry TSRMLS_CC)) { *int_key = iter->index; return HASH_KEY_IS_LONG; } else { curobj = iterator->curobj; intern = (dom_object *)zend_object_store_get_object(curobj TSRMLS_CC); if (intern != NULL && intern->ptr != NULL) { curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node; } else { return HASH_KEY_NON_EXISTANT; } namelen = xmlStrlen(curnode->name); *str_key = estrndup(curnode->name, namelen); *str_key_len = namelen + 1; return HASH_KEY_IS_STRING; } } /* }}} */ static void php_dom_iterator_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ { zval *curobj, *curattr = NULL; zval *object; xmlNodePtr curnode = NULL, basenode; dom_object *intern; dom_object *nnmap; dom_nnodemap_object *objmap; int ret, previndex=0; HashTable *nodeht; zval **entry; php_dom_iterator *iterator = (php_dom_iterator *)iter; object = (zval *)iterator->intern.data; nnmap = (dom_object *)zend_object_store_get_object(object TSRMLS_CC); objmap = (dom_nnodemap_object *)nnmap->ptr; curobj = iterator->curobj; intern = (dom_object *)zend_object_store_get_object(curobj TSRMLS_CC); if (intern != NULL && intern->ptr != NULL) { if (objmap->nodetype != XML_ENTITY_NODE && objmap->nodetype != XML_NOTATION_NODE) { if (objmap->nodetype == DOM_NODESET) { nodeht = HASH_OF(objmap->baseobjptr); zend_hash_move_forward(nodeht); if (zend_hash_get_current_data(nodeht, (void **) &entry)==SUCCESS) { curattr = *entry; Z_ADDREF_P(curattr); } } else { curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node; if (objmap->nodetype == XML_ATTRIBUTE_NODE || objmap->nodetype == XML_ELEMENT_NODE) { curnode = curnode->next; } else { /* Nav the tree evey time as this is LIVE */ basenode = dom_object_get_node(objmap->baseobj); if (basenode && (basenode->type == XML_DOCUMENT_NODE || basenode->type == XML_HTML_DOCUMENT_NODE)) { basenode = xmlDocGetRootElement((xmlDoc *) basenode); } else if (basenode) { basenode = basenode->children; } else { goto err; } curnode = dom_get_elements_by_tag_name_ns_raw(basenode, objmap->ns, objmap->local, &previndex, iter->index); } } } else { if (objmap->nodetype == XML_ENTITY_NODE) { curnode = php_dom_libxml_hash_iter(objmap->ht, iter->index); } else { curnode = php_dom_libxml_notation_iter(objmap->ht, iter->index); } } } err: zval_ptr_dtor((zval**)&curobj); if (curnode) { MAKE_STD_ZVAL(curattr); curattr = php_dom_create_object(curnode, &ret, NULL, curattr, objmap->baseobj TSRMLS_CC); } iterator->curobj = curattr; } /* }}} */ zend_object_iterator_funcs php_dom_iterator_funcs = { php_dom_iterator_dtor, php_dom_iterator_valid, php_dom_iterator_current_data, php_dom_iterator_current_key, php_dom_iterator_move_forward, NULL }; zend_object_iterator *php_dom_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */ { dom_object *intern; dom_nnodemap_object *objmap; xmlNodePtr nodep, curnode=NULL; zval *curattr = NULL; int ret, curindex = 0; HashTable *nodeht; zval **entry; php_dom_iterator *iterator; if (by_ref) { zend_error(E_ERROR, "An iterator cannot be used with foreach by reference"); } iterator = emalloc(sizeof(php_dom_iterator)); Z_ADDREF_P(object); iterator->intern.data = (void*)object; iterator->intern.funcs = &php_dom_iterator_funcs; intern = (dom_object *)zend_object_store_get_object(object TSRMLS_CC); objmap = (dom_nnodemap_object *)intern->ptr; if (objmap != NULL) { if (objmap->nodetype != XML_ENTITY_NODE && objmap->nodetype != XML_NOTATION_NODE) { if (objmap->nodetype == DOM_NODESET) { nodeht = HASH_OF(objmap->baseobjptr); zend_hash_internal_pointer_reset(nodeht); if (zend_hash_get_current_data(nodeht, (void **) &entry)==SUCCESS) { curattr = *entry; Z_ADDREF_P(curattr); } } else { nodep = (xmlNode *)dom_object_get_node(objmap->baseobj); if (!nodep) { goto err; } if (objmap->nodetype == XML_ATTRIBUTE_NODE || objmap->nodetype == XML_ELEMENT_NODE) { if (objmap->nodetype == XML_ATTRIBUTE_NODE) { curnode = (xmlNodePtr) nodep->properties; } else { curnode = (xmlNodePtr) nodep->children; } } else { if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) { nodep = xmlDocGetRootElement((xmlDoc *) nodep); } else { nodep = nodep->children; } curnode = dom_get_elements_by_tag_name_ns_raw(nodep, objmap->ns, objmap->local, &curindex, 0); } } } else { if (objmap->nodetype == XML_ENTITY_NODE) { curnode = php_dom_libxml_hash_iter(objmap->ht, 0); } else { curnode = php_dom_libxml_notation_iter(objmap->ht, 0); } } } err: if (curnode) { MAKE_STD_ZVAL(curattr); curattr = php_dom_create_object(curnode, &ret, NULL, curattr, objmap->baseobj TSRMLS_CC); } iterator->curobj = curattr; return (zend_object_iterator*)iterator; } /* }}} */ #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */