1/* 2 +----------------------------------------------------------------------+ 3 | PHP Version 5 | 4 +----------------------------------------------------------------------+ 5 | Copyright (c) 1997-2013 The PHP Group | 6 +----------------------------------------------------------------------+ 7 | This source file is subject to version 3.01 of the PHP license, | 8 | that is bundled with this package in the file LICENSE, and is | 9 | available through the world-wide-web at the following url: | 10 | http://www.php.net/license/3_01.txt | 11 | If you did not receive a copy of the PHP license and are unable to | 12 | obtain it through the world-wide-web, please send a note to | 13 | license@php.net so we can mail you a copy immediately. | 14 +----------------------------------------------------------------------+ 15 | Authors: Christian Stocker <chregu@php.net> | 16 | Rob Richards <rrichards@php.net> | 17 +----------------------------------------------------------------------+ 18*/ 19 20/* $Id$ */ 21 22#ifdef HAVE_CONFIG_H 23#include "config.h" 24#endif 25 26#include "php.h" 27#if HAVE_LIBXML && HAVE_DOM 28#include "php_dom.h" 29#include "dom_ce.h" 30 31typedef struct _nodeIterator nodeIterator; 32struct _nodeIterator { 33 int cur; 34 int index; 35 xmlNode *node; 36}; 37 38typedef struct _notationIterator notationIterator; 39struct _notationIterator { 40 int cur; 41 int index; 42 xmlNotation *notation; 43}; 44 45static void itemHashScanner (void *payload, void *data, xmlChar *name) /* {{{ */ 46{ 47 nodeIterator *priv = (nodeIterator *)data; 48 49 if(priv->cur < priv->index) { 50 priv->cur++; 51 } else { 52 if(priv->node == NULL) { 53 priv->node = (xmlNode *)payload; 54 } 55 } 56} 57/* }}} */ 58 59xmlNodePtr create_notation(const xmlChar *name, const xmlChar *ExternalID, const xmlChar *SystemID) /* {{{ */ 60{ 61 xmlEntityPtr ret; 62 63 ret = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity)); 64 memset(ret, 0, sizeof(xmlEntity)); 65 ret->type = XML_NOTATION_NODE; 66 ret->name = xmlStrdup(name); 67 ret->ExternalID = xmlStrdup(ExternalID); 68 ret->SystemID = xmlStrdup(SystemID); 69 ret->length = 0; 70 ret->content = NULL; 71 ret->URI = NULL; 72 ret->orig = NULL; 73 ret->children = NULL; 74 ret->parent = NULL; 75 ret->doc = NULL; 76 ret->_private = NULL; 77 ret->last = NULL; 78 ret->prev = NULL; 79 return((xmlNodePtr) ret); 80} 81/* }}} */ 82 83xmlNode *php_dom_libxml_hash_iter(xmlHashTable *ht, int index) /* {{{ */ 84{ 85 xmlNode *nodep = NULL; 86 nodeIterator *iter; 87 int htsize; 88 89 if ((htsize = xmlHashSize(ht)) > 0 && index < htsize) { 90 iter = emalloc(sizeof(nodeIterator)); 91 iter->cur = 0; 92 iter->index = index; 93 iter->node = NULL; 94 xmlHashScan(ht, itemHashScanner, iter); 95 nodep = iter->node; 96 efree(iter); 97 return nodep; 98 } else { 99 return NULL; 100 } 101} 102/* }}} */ 103 104xmlNode *php_dom_libxml_notation_iter(xmlHashTable *ht, int index) /* {{{ */ 105{ 106 notationIterator *iter; 107 xmlNotation *notep = NULL; 108 int htsize; 109 110 if ((htsize = xmlHashSize(ht)) > 0 && index < htsize) { 111 iter = emalloc(sizeof(notationIterator)); 112 iter->cur = 0; 113 iter->index = index; 114 iter->notation = NULL; 115 xmlHashScan(ht, itemHashScanner, iter); 116 notep = iter->notation; 117 efree(iter); 118 return create_notation(notep->name, notep->PublicID, notep->SystemID); 119 } else { 120 return NULL; 121 } 122} 123/* }}} */ 124 125static void php_dom_iterator_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ 126{ 127 php_dom_iterator *iterator = (php_dom_iterator *)iter; 128 129 zval_ptr_dtor((zval**)&iterator->intern.data); 130 131 if (iterator->curobj) { 132 zval_ptr_dtor((zval**)&iterator->curobj); 133 } 134 135 efree(iterator); 136} 137/* }}} */ 138 139static int php_dom_iterator_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ 140{ 141 142 php_dom_iterator *iterator = (php_dom_iterator *)iter; 143 144 if (iterator->curobj) { 145 return SUCCESS; 146 } else { 147 return FAILURE; 148 } 149} 150/* }}} */ 151 152static void php_dom_iterator_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */ 153{ 154 php_dom_iterator *iterator = (php_dom_iterator *)iter; 155 156 *data = &iterator->curobj; 157} 158/* }}} */ 159 160static int php_dom_iterator_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */ 161{ 162 zval *curobj; 163 xmlNodePtr curnode = NULL; 164 dom_object *intern; 165 zval *object; 166 int namelen; 167 168 php_dom_iterator *iterator = (php_dom_iterator *)iter; 169 170 object = (zval *)iterator->intern.data; 171 172 if (instanceof_function(Z_OBJCE_P(object), dom_nodelist_class_entry TSRMLS_CC)) { 173 *int_key = iter->index; 174 return HASH_KEY_IS_LONG; 175 } else { 176 curobj = iterator->curobj; 177 178 intern = (dom_object *)zend_object_store_get_object(curobj TSRMLS_CC); 179 if (intern != NULL && intern->ptr != NULL) { 180 curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node; 181 } else { 182 return HASH_KEY_NON_EXISTANT; 183 } 184 185 namelen = xmlStrlen(curnode->name); 186 *str_key = estrndup(curnode->name, namelen); 187 *str_key_len = namelen + 1; 188 return HASH_KEY_IS_STRING; 189 } 190} 191/* }}} */ 192 193static void php_dom_iterator_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ 194{ 195 zval *curobj, *curattr = NULL; 196 zval *object; 197 xmlNodePtr curnode = NULL, basenode; 198 dom_object *intern; 199 dom_object *nnmap; 200 dom_nnodemap_object *objmap; 201 int ret, previndex=0; 202 HashTable *nodeht; 203 zval **entry; 204 205 php_dom_iterator *iterator = (php_dom_iterator *)iter; 206 207 object = (zval *)iterator->intern.data; 208 nnmap = (dom_object *)zend_object_store_get_object(object TSRMLS_CC); 209 objmap = (dom_nnodemap_object *)nnmap->ptr; 210 211 curobj = iterator->curobj; 212 intern = (dom_object *)zend_object_store_get_object(curobj TSRMLS_CC); 213 if (intern != NULL && intern->ptr != NULL) { 214 if (objmap->nodetype != XML_ENTITY_NODE && 215 objmap->nodetype != XML_NOTATION_NODE) { 216 if (objmap->nodetype == DOM_NODESET) { 217 nodeht = HASH_OF(objmap->baseobjptr); 218 zend_hash_move_forward(nodeht); 219 if (zend_hash_get_current_data(nodeht, (void **) &entry)==SUCCESS) { 220 curattr = *entry; 221 Z_ADDREF_P(curattr); 222 } 223 } else { 224 curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node; 225 if (objmap->nodetype == XML_ATTRIBUTE_NODE || 226 objmap->nodetype == XML_ELEMENT_NODE) { 227 curnode = curnode->next; 228 } else { 229 /* Nav the tree evey time as this is LIVE */ 230 basenode = dom_object_get_node(objmap->baseobj); 231 if (basenode && (basenode->type == XML_DOCUMENT_NODE || 232 basenode->type == XML_HTML_DOCUMENT_NODE)) { 233 basenode = xmlDocGetRootElement((xmlDoc *) basenode); 234 } else if (basenode) { 235 basenode = basenode->children; 236 } else { 237 goto err; 238 } 239 curnode = dom_get_elements_by_tag_name_ns_raw(basenode, objmap->ns, objmap->local, &previndex, iter->index); 240 } 241 } 242 } else { 243 if (objmap->nodetype == XML_ENTITY_NODE) { 244 curnode = php_dom_libxml_hash_iter(objmap->ht, iter->index); 245 } else { 246 curnode = php_dom_libxml_notation_iter(objmap->ht, iter->index); 247 } 248 } 249 } 250err: 251 zval_ptr_dtor((zval**)&curobj); 252 if (curnode) { 253 MAKE_STD_ZVAL(curattr); 254 curattr = php_dom_create_object(curnode, &ret, curattr, objmap->baseobj TSRMLS_CC); 255 } 256 257 iterator->curobj = curattr; 258} 259/* }}} */ 260 261zend_object_iterator_funcs php_dom_iterator_funcs = { 262 php_dom_iterator_dtor, 263 php_dom_iterator_valid, 264 php_dom_iterator_current_data, 265 php_dom_iterator_current_key, 266 php_dom_iterator_move_forward, 267 NULL 268}; 269 270zend_object_iterator *php_dom_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */ 271{ 272 dom_object *intern; 273 dom_nnodemap_object *objmap; 274 xmlNodePtr nodep, curnode=NULL; 275 zval *curattr = NULL; 276 int ret, curindex = 0; 277 HashTable *nodeht; 278 zval **entry; 279 php_dom_iterator *iterator; 280 281 if (by_ref) { 282 zend_error(E_ERROR, "An iterator cannot be used with foreach by reference"); 283 } 284 iterator = emalloc(sizeof(php_dom_iterator)); 285 286 Z_ADDREF_P(object); 287 iterator->intern.data = (void*)object; 288 iterator->intern.funcs = &php_dom_iterator_funcs; 289 290 intern = (dom_object *)zend_object_store_get_object(object TSRMLS_CC); 291 objmap = (dom_nnodemap_object *)intern->ptr; 292 if (objmap != NULL) { 293 if (objmap->nodetype != XML_ENTITY_NODE && 294 objmap->nodetype != XML_NOTATION_NODE) { 295 if (objmap->nodetype == DOM_NODESET) { 296 nodeht = HASH_OF(objmap->baseobjptr); 297 zend_hash_internal_pointer_reset(nodeht); 298 if (zend_hash_get_current_data(nodeht, (void **) &entry)==SUCCESS) { 299 curattr = *entry; 300 Z_ADDREF_P(curattr); 301 } 302 } else { 303 nodep = (xmlNode *)dom_object_get_node(objmap->baseobj); 304 if (!nodep) { 305 goto err; 306 } 307 if (objmap->nodetype == XML_ATTRIBUTE_NODE || objmap->nodetype == XML_ELEMENT_NODE) { 308 if (objmap->nodetype == XML_ATTRIBUTE_NODE) { 309 curnode = (xmlNodePtr) nodep->properties; 310 } else { 311 curnode = (xmlNodePtr) nodep->children; 312 } 313 } else { 314 if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) { 315 nodep = xmlDocGetRootElement((xmlDoc *) nodep); 316 } else { 317 nodep = nodep->children; 318 } 319 curnode = dom_get_elements_by_tag_name_ns_raw(nodep, objmap->ns, objmap->local, &curindex, 0); 320 } 321 } 322 } else { 323 if (objmap->nodetype == XML_ENTITY_NODE) { 324 curnode = php_dom_libxml_hash_iter(objmap->ht, 0); 325 } else { 326 curnode = php_dom_libxml_notation_iter(objmap->ht, 0); 327 } 328 } 329 } 330err: 331 if (curnode) { 332 MAKE_STD_ZVAL(curattr); 333 curattr = php_dom_create_object(curnode, &ret, curattr, objmap->baseobj TSRMLS_CC); 334 } 335 336 iterator->curobj = curattr; 337 338 return (zend_object_iterator*)iterator; 339} 340/* }}} */ 341 342#endif 343 344/* 345 * Local variables: 346 * tab-width: 4 347 * c-basic-offset: 4 348 * End: 349 * vim600: noet sw=4 ts=4 fdm=marker 350 * vim<600: noet sw=4 ts=4 351 */ 352