root/ext/dom/dom_iterators.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. itemHashScanner
  2. create_notation
  3. php_dom_libxml_hash_iter
  4. php_dom_libxml_notation_iter
  5. php_dom_iterator_dtor
  6. php_dom_iterator_valid
  7. php_dom_iterator_current_data
  8. php_dom_iterator_current_key
  9. php_dom_iterator_move_forward
  10. php_dom_get_iterator

/*
   +----------------------------------------------------------------------+
   | PHP Version 5                                                        |
   +----------------------------------------------------------------------+
   | Copyright (c) 1997-2008 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 <chregu@php.net>                          |
   |          Rob Richards <rrichards@php.net>                            |
   +----------------------------------------------------------------------+
*/

/* $Id: dom_iterators.c,v 1.9.2.3.2.6 2007/12/31 07:20:05 sebastian Exp $ */

#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;
                                        curattr->refcount++;
                                }
                        } 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));

        object->refcount++;
        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;
                                        curattr->refcount++;
                                }
                        } 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

/* [<][>][^][v][top][bottom][index][help] */