PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: directory - spl - spl_iterators.c (source / functions) Found Hit Coverage
Test: PHP Code Coverage Lines: 1500 1375 91.7 %
Date: 2012-05-14 Functions: 145 145 100.0 %
Colors: not hit hit

       1                 : /*
       2                 :    +----------------------------------------------------------------------+
       3                 :    | PHP Version 5                                                        |
       4                 :    +----------------------------------------------------------------------+
       5                 :    | Copyright (c) 1997-2012 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: Marcus Boerger <helly@php.net>                              |
      16                 :    +----------------------------------------------------------------------+
      17                 :  */
      18                 : 
      19                 : /* $Id$ */
      20                 : 
      21                 : #ifdef HAVE_CONFIG_H
      22                 : # include "config.h"
      23                 : #endif
      24                 : 
      25                 : #include "php.h"
      26                 : #include "php_ini.h"
      27                 : #include "ext/standard/info.h"
      28                 : #include "zend_exceptions.h"
      29                 : #include "zend_interfaces.h"
      30                 : 
      31                 : #include "php_spl.h"
      32                 : #include "spl_functions.h"
      33                 : #include "spl_engine.h"
      34                 : #include "spl_iterators.h"
      35                 : #include "spl_directory.h"
      36                 : #include "spl_array.h"
      37                 : #include "spl_exceptions.h"
      38                 : #include "ext/standard/php_smart_str.h"
      39                 : 
      40                 : #ifdef accept
      41                 : #undef accept
      42                 : #endif
      43                 : 
      44                 : PHPAPI zend_class_entry *spl_ce_RecursiveIterator;
      45                 : PHPAPI zend_class_entry *spl_ce_RecursiveIteratorIterator;
      46                 : PHPAPI zend_class_entry *spl_ce_FilterIterator;
      47                 : PHPAPI zend_class_entry *spl_ce_RecursiveFilterIterator;
      48                 : PHPAPI zend_class_entry *spl_ce_ParentIterator;
      49                 : PHPAPI zend_class_entry *spl_ce_SeekableIterator;
      50                 : PHPAPI zend_class_entry *spl_ce_LimitIterator;
      51                 : PHPAPI zend_class_entry *spl_ce_CachingIterator;
      52                 : PHPAPI zend_class_entry *spl_ce_RecursiveCachingIterator;
      53                 : PHPAPI zend_class_entry *spl_ce_OuterIterator;
      54                 : PHPAPI zend_class_entry *spl_ce_IteratorIterator;
      55                 : PHPAPI zend_class_entry *spl_ce_NoRewindIterator;
      56                 : PHPAPI zend_class_entry *spl_ce_InfiniteIterator;
      57                 : PHPAPI zend_class_entry *spl_ce_EmptyIterator;
      58                 : PHPAPI zend_class_entry *spl_ce_AppendIterator;
      59                 : PHPAPI zend_class_entry *spl_ce_RegexIterator;
      60                 : PHPAPI zend_class_entry *spl_ce_RecursiveRegexIterator;
      61                 : PHPAPI zend_class_entry *spl_ce_Countable;
      62                 : PHPAPI zend_class_entry *spl_ce_RecursiveTreeIterator;
      63                 : 
      64                 : ZEND_BEGIN_ARG_INFO(arginfo_recursive_it_void, 0)
      65                 : ZEND_END_ARG_INFO()
      66                 : 
      67                 : const zend_function_entry spl_funcs_RecursiveIterator[] = {
      68                 :         SPL_ABSTRACT_ME(RecursiveIterator, hasChildren,  arginfo_recursive_it_void)
      69                 :         SPL_ABSTRACT_ME(RecursiveIterator, getChildren,  arginfo_recursive_it_void)
      70                 :         PHP_FE_END
      71                 : };
      72                 : 
      73                 : typedef enum {
      74                 :         RIT_LEAVES_ONLY = 0,
      75                 :         RIT_SELF_FIRST  = 1,
      76                 :         RIT_CHILD_FIRST = 2
      77                 : } RecursiveIteratorMode;
      78                 : 
      79                 : #define RIT_CATCH_GET_CHILD CIT_CATCH_GET_CHILD
      80                 : 
      81                 : typedef enum {
      82                 :         RTIT_BYPASS_CURRENT = 4,
      83                 :         RTIT_BYPASS_KEY     = 8
      84                 : } RecursiveTreeIteratorFlags;
      85                 : 
      86                 : typedef enum {
      87                 :         RS_NEXT  = 0,
      88                 :         RS_TEST  = 1,
      89                 :         RS_SELF  = 2,
      90                 :         RS_CHILD = 3,
      91                 :         RS_START = 4
      92                 : } RecursiveIteratorState;
      93                 : 
      94                 : typedef struct _spl_sub_iterator {
      95                 :         zend_object_iterator    *iterator;
      96                 :         zval                    *zobject;
      97                 :         zend_class_entry        *ce;
      98                 :         RecursiveIteratorState  state;
      99                 : } spl_sub_iterator;
     100                 : 
     101                 : typedef struct _spl_recursive_it_object {
     102                 :         zend_object              std;
     103                 :         spl_sub_iterator         *iterators;
     104                 :         int                      level;
     105                 :         RecursiveIteratorMode    mode;
     106                 :         int                      flags;
     107                 :         int                      max_depth;
     108                 :         zend_bool                in_iteration;
     109                 :         zend_function            *beginIteration;
     110                 :         zend_function            *endIteration;
     111                 :         zend_function            *callHasChildren;
     112                 :         zend_function            *callGetChildren;
     113                 :         zend_function            *beginChildren;
     114                 :         zend_function            *endChildren;
     115                 :         zend_function            *nextElement;
     116                 :         zend_class_entry         *ce;
     117                 :         smart_str                prefix[6];
     118                 : } spl_recursive_it_object;
     119                 : 
     120                 : typedef struct _spl_recursive_it_iterator {
     121                 :         zend_object_iterator   intern;
     122                 :         zval                   *zobject;
     123                 : } spl_recursive_it_iterator;
     124                 : 
     125                 : static zend_object_handlers spl_handlers_rec_it_it;
     126                 : static zend_object_handlers spl_handlers_dual_it;
     127                 : 
     128                 : #define SPL_FETCH_AND_CHECK_DUAL_IT(var, objzval) \
     129                 :         do { \
     130                 :                 spl_dual_it_object *it = zend_object_store_get_object((objzval) TSRMLS_CC); \
     131                 :                 if (it->dit_type == DIT_Unknown) { \
     132                 :                         zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, \
     133                 :                                 "The object is in an invalid state as the parent constructor was not called"); \
     134                 :                         return; \
     135                 :                 } \
     136                 :                 (var) = it; \
     137                 :         } while (0)
     138                 : 
     139              60 : static void spl_recursive_it_dtor(zend_object_iterator *_iter TSRMLS_DC)
     140                 : {
     141              60 :         spl_recursive_it_iterator *iter   = (spl_recursive_it_iterator*)_iter;
     142              60 :         spl_recursive_it_object   *object = (spl_recursive_it_object*)_iter->data;
     143                 :         zend_object_iterator      *sub_iter;
     144                 : 
     145             120 :         while (object->level > 0) {
     146               0 :                 sub_iter = object->iterators[object->level].iterator;
     147               0 :                 sub_iter->funcs->dtor(sub_iter TSRMLS_CC);
     148               0 :                 zval_ptr_dtor(&object->iterators[object->level--].zobject);
     149                 :         }
     150              60 :         object->iterators = erealloc(object->iterators, sizeof(spl_sub_iterator));
     151              60 :         object->level = 0;
     152                 : 
     153              60 :         zval_ptr_dtor(&iter->zobject);
     154              60 :         efree(iter);
     155              60 : }
     156                 : 
     157            2010 : static int spl_recursive_it_valid_ex(spl_recursive_it_object *object, zval *zthis TSRMLS_DC)
     158                 : {
     159                 :         zend_object_iterator      *sub_iter;
     160            2010 :         int                       level = object->level;
     161                 :         
     162            4119 :         while (level >=0) {
     163            2010 :                 sub_iter = object->iterators[level].iterator;
     164            2010 :                 if (sub_iter->funcs->valid(sub_iter TSRMLS_CC) == SUCCESS) {
     165            1911 :                         return SUCCESS;
     166                 :                 }
     167              99 :                 level--;
     168                 :         }
     169              99 :         if (object->endIteration && object->in_iteration) {
     170               5 :                 zend_call_method_with_0_params(&zthis, object->ce, &object->endIteration, "endIteration", NULL);
     171                 :         }
     172              99 :         object->in_iteration = 0;
     173              99 :         return FAILURE;
     174                 : }
     175                 : 
     176            1635 : static int spl_recursive_it_valid(zend_object_iterator *iter TSRMLS_DC)
     177                 : {
     178            1635 :         spl_recursive_it_object   *object = (spl_recursive_it_object*)iter->data;
     179                 :         
     180            1635 :         return spl_recursive_it_valid_ex(object, ((spl_recursive_it_iterator*)iter)->zobject TSRMLS_CC);
     181                 : }
     182                 : 
     183            1575 : static void spl_recursive_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
     184                 : {
     185            1575 :         spl_recursive_it_object   *object = (spl_recursive_it_object*)iter->data;
     186            1575 :         zend_object_iterator      *sub_iter = object->iterators[object->level].iterator;
     187                 :         
     188            1575 :         sub_iter->funcs->get_current_data(sub_iter, data TSRMLS_CC);
     189            1575 : }
     190                 : 
     191            1403 : static int spl_recursive_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
     192                 : {
     193            1403 :         spl_recursive_it_object   *object = (spl_recursive_it_object*)iter->data;
     194            1403 :         zend_object_iterator      *sub_iter = object->iterators[object->level].iterator;
     195                 : 
     196            1403 :         if (sub_iter->funcs->get_current_key) {
     197            1403 :                 return sub_iter->funcs->get_current_key(sub_iter, str_key, str_key_len, int_key TSRMLS_CC);
     198                 :         } else {
     199               0 :                 *int_key = iter->index;
     200               0 :                 return HASH_KEY_IS_LONG;
     201                 :         }
     202                 : }
     203                 : 
     204            2035 : static void spl_recursive_it_move_forward_ex(spl_recursive_it_object *object, zval *zthis TSRMLS_DC)
     205                 : {
     206                 :         zend_object_iterator      *iterator;
     207                 :         zval                      *zobject;
     208                 :         zend_class_entry          *ce;
     209                 :         zval                      *retval, *child;
     210                 :         zend_object_iterator      *sub_iter;
     211                 :         int                       has_children;
     212                 : 
     213            4325 :         while (!EG(exception)) {
     214                 : next_step:
     215            2823 :                 iterator = object->iterators[object->level].iterator;
     216            2823 :                 switch (object->iterators[object->level].state) {
     217                 :                         case RS_NEXT:
     218            2084 :                                 iterator->funcs->move_forward(iterator TSRMLS_CC);
     219            2084 :                                 if (EG(exception)) {
     220               1 :                                         if (!(object->flags & RIT_CATCH_GET_CHILD)) {
     221               1 :                                                 return;
     222                 :                                         } else {
     223               0 :                                                 zend_clear_exception(TSRMLS_C);
     224                 :                                         }
     225                 :                                 }
     226                 :                         case RS_START:
     227            2469 :                                 if (iterator->funcs->valid(iterator TSRMLS_CC) == FAILURE) {
     228             355 :                                         break;
     229                 :                                 }
     230            2114 :                                 object->iterators[object->level].state = RS_TEST;                                 
     231                 :                                 /* break; */
     232                 :                         case RS_TEST:
     233            2114 :                                 ce = object->iterators[object->level].ce;
     234            2114 :                                 zobject = object->iterators[object->level].zobject;
     235            2114 :                                 if (object->callHasChildren) {
     236              45 :                                         zend_call_method_with_0_params(&zthis, object->ce, &object->callHasChildren, "callHasChildren", &retval);
     237                 :                                 } else {
     238            2069 :                                         zend_call_method_with_0_params(&zobject, ce, NULL, "haschildren", &retval);
     239                 :                                 }
     240            2114 :                                 if (EG(exception)) {
     241               2 :                                         if (!(object->flags & RIT_CATCH_GET_CHILD)) {
     242               1 :                                                 object->iterators[object->level].state = RS_NEXT;
     243               1 :                                                 return;
     244                 :                                         } else {
     245               1 :                                                 zend_clear_exception(TSRMLS_C);
     246                 :                                         }
     247                 :                                 }
     248            2113 :                                 if (retval) {
     249            2112 :                                         has_children = zend_is_true(retval);
     250            2112 :                                         zval_ptr_dtor(&retval);
     251            2112 :                                         if (has_children) {
     252             270 :                                                 if (object->max_depth == -1 || object->max_depth > object->level) {
     253             267 :                                                         switch (object->mode) {
     254                 :                                                         case RIT_LEAVES_ONLY:
     255                 :                                                         case RIT_CHILD_FIRST:
     256             187 :                                                                 object->iterators[object->level].state = RS_CHILD;
     257             187 :                                                                 goto next_step;
     258                 :                                                         case RIT_SELF_FIRST:
     259              80 :                                                                 object->iterators[object->level].state = RS_SELF;
     260              80 :                                                                 goto next_step;
     261                 :                                                         }
     262                 :                                                 } else {
     263                 :                                                         /* do not recurse into */
     264               3 :                                                         if (object->mode == RIT_LEAVES_ONLY) {
     265                 :                                                                 /* this is not a leave, so skip it */
     266               3 :                                                                 object->iterators[object->level].state = RS_NEXT;
     267               3 :                                                                 goto next_step;
     268                 :                                                         }
     269                 :                                                 }
     270                 :                                         }
     271                 :                                 }
     272            1843 :                                 if (object->nextElement) {
     273               9 :                                         zend_call_method_with_0_params(&zthis, object->ce, &object->nextElement, "nextelement", NULL);
     274                 :                                 }
     275            1843 :                                 object->iterators[object->level].state = RS_NEXT;
     276            1843 :                                 if (EG(exception)) {
     277               2 :                                         if (!(object->flags & RIT_CATCH_GET_CHILD)) {
     278               1 :                                                 return;
     279                 :                                         } else {
     280               1 :                                                 zend_clear_exception(TSRMLS_C);
     281                 :                                         }
     282                 :                                 }
     283            1842 :                                 return /* self */;
     284                 :                         case RS_SELF:
     285              87 :                                 if (object->nextElement && (object->mode == RIT_SELF_FIRST || object->mode == RIT_CHILD_FIRST)) {
     286               1 :                                         zend_call_method_with_0_params(&zthis, object->ce, &object->nextElement, "nextelement", NULL);
     287                 :                                 }
     288              87 :                                 if (object->mode == RIT_SELF_FIRST) {
     289              80 :                                         object->iterators[object->level].state = RS_CHILD;
     290                 :                                 } else {
     291               7 :                                         object->iterators[object->level].state = RS_NEXT;
     292                 :                                 }
     293              87 :                                 return /* self */;
     294                 :                         case RS_CHILD:
     295             266 :                                 ce = object->iterators[object->level].ce;
     296             266 :                                 zobject = object->iterators[object->level].zobject;
     297             266 :                                 if (object->callGetChildren) {
     298               8 :                                         zend_call_method_with_0_params(&zthis, object->ce, &object->callGetChildren, "callGetChildren", &child);
     299                 :                                 } else {
     300             258 :                                         zend_call_method_with_0_params(&zobject, ce, NULL, "getchildren", &child);
     301                 :                                 }
     302                 : 
     303             266 :                                 if (EG(exception)) {
     304               1 :                                         if (!(object->flags & RIT_CATCH_GET_CHILD)) {
     305               0 :                                                 return;
     306                 :                                         } else {
     307               1 :                                                 zend_clear_exception(TSRMLS_C);
     308               1 :                                                 if (child) {
     309               0 :                                                         zval_ptr_dtor(&child);
     310                 :                                                 }
     311               1 :                                                 object->iterators[object->level].state = RS_NEXT;
     312               1 :                                                 goto next_step;
     313                 :                                         }
     314                 :                                 }
     315                 : 
     316             265 :                                 ce = child && Z_TYPE_P(child) == IS_OBJECT ? Z_OBJCE_P(child) : NULL;
     317             265 :                                 if (!ce || !instanceof_function(ce, spl_ce_RecursiveIterator TSRMLS_CC)) {
     318               1 :                                         if (child) {
     319               1 :                                                 zval_ptr_dtor(&child);
     320                 :                                         }
     321               1 :                                         zend_throw_exception(spl_ce_UnexpectedValueException, "Objects returned by RecursiveIterator::getChildren() must implement RecursiveIterator", 0 TSRMLS_CC);
     322               1 :                                         return;
     323                 :                                 }
     324             264 :                                 if (object->mode == RIT_CHILD_FIRST) {
     325               7 :                                         object->iterators[object->level].state = RS_SELF;
     326                 :                                 } else {
     327             257 :                                         object->iterators[object->level].state = RS_NEXT;
     328                 :                                 }
     329             264 :                                 object->iterators = erealloc(object->iterators, sizeof(spl_sub_iterator) * (++object->level+1));
     330             264 :                                 sub_iter = ce->get_iterator(ce, child, 0 TSRMLS_CC);
     331             264 :                                 object->iterators[object->level].iterator = sub_iter;
     332             264 :                                 object->iterators[object->level].zobject = child;
     333             264 :                                 object->iterators[object->level].ce = ce;
     334             264 :                                 object->iterators[object->level].state = RS_START;
     335             264 :                                 if (sub_iter->funcs->rewind) {
     336             264 :                                         sub_iter->funcs->rewind(sub_iter TSRMLS_CC);
     337                 :                                 }
     338             264 :                                 if (object->beginChildren) {
     339              30 :                                         zend_call_method_with_0_params(&zthis, object->ce, &object->beginChildren, "beginchildren", NULL);
     340              30 :                                         if (EG(exception)) {
     341               2 :                                                 if (!(object->flags & RIT_CATCH_GET_CHILD)) {
     342               1 :                                                         return;
     343                 :                                                 } else {
     344               1 :                                                         zend_clear_exception(TSRMLS_C);
     345                 :                                                 }
     346                 :                                         }
     347                 :                                 }
     348             263 :                                 goto next_step;
     349                 :                 }
     350                 :                 /* no more elements */
     351             355 :                 if (object->level > 0) {
     352             256 :                         if (object->endChildren) {
     353              33 :                                 zend_call_method_with_0_params(&zthis, object->ce, &object->endChildren, "endchildren", NULL);
     354              33 :                                 if (EG(exception)) {
     355               2 :                                         if (!(object->flags & RIT_CATCH_GET_CHILD)) {
     356               1 :                                                 return;
     357                 :                                         } else {
     358               1 :                                                 zend_clear_exception(TSRMLS_C);
     359                 :                                         }
     360                 :                                 }
     361                 :                         }
     362             255 :                         iterator->funcs->dtor(iterator TSRMLS_CC);
     363             255 :                         zval_ptr_dtor(&object->iterators[object->level].zobject);
     364             255 :                         object->level--;
     365                 :                 } else {
     366              99 :                         return; /* done completeley */
     367                 :                 }
     368                 :         }
     369                 : }
     370                 : 
     371             115 : static void spl_recursive_it_rewind_ex(spl_recursive_it_object *object, zval *zthis TSRMLS_DC)
     372                 : {
     373                 :         zend_object_iterator      *sub_iter;
     374                 :         
     375             115 :         if (!object->iterators) {
     376               1 :                 php_error_docref(NULL TSRMLS_CC, E_ERROR, "The %s instance wasn't initialized properly", Z_OBJCE_P(zthis)->name);
     377                 :         }
     378                 : 
     379             230 :         while (object->level) {
     380               2 :                 sub_iter = object->iterators[object->level].iterator;
     381               2 :                 sub_iter->funcs->dtor(sub_iter TSRMLS_CC);
     382               2 :                 zval_ptr_dtor(&object->iterators[object->level--].zobject);
     383               2 :                 if (!EG(exception) && (!object->endChildren || object->endChildren->common.scope != spl_ce_RecursiveIteratorIterator)) {
     384               2 :                         zend_call_method_with_0_params(&zthis, object->ce, &object->endChildren, "endchildren", NULL);
     385                 :                 }
     386                 :         }
     387             114 :         object->iterators = erealloc(object->iterators, sizeof(spl_sub_iterator));
     388             114 :         object->iterators[0].state = RS_START;
     389             114 :         sub_iter = object->iterators[0].iterator;
     390             114 :         if (sub_iter->funcs->rewind) {
     391             114 :                 sub_iter->funcs->rewind(sub_iter TSRMLS_CC);
     392                 :         }
     393             114 :         if (!EG(exception) && object->beginIteration && !object->in_iteration) {
     394               5 :                 zend_call_method_with_0_params(&zthis, object->ce, &object->beginIteration, "beginIteration", NULL);
     395                 :         }
     396             114 :         object->in_iteration = 1;
     397             114 :         spl_recursive_it_move_forward_ex(object, zthis TSRMLS_CC);
     398             114 : }
     399                 : 
     400            1577 : static void spl_recursive_it_move_forward(zend_object_iterator *iter TSRMLS_DC)
     401                 : {
     402            1577 :         spl_recursive_it_move_forward_ex((spl_recursive_it_object*)iter->data, ((spl_recursive_it_iterator*)iter)->zobject TSRMLS_CC);
     403            1577 : }
     404                 : 
     405              61 : static void spl_recursive_it_rewind(zend_object_iterator *iter TSRMLS_DC)
     406                 : {
     407              61 :         spl_recursive_it_rewind_ex((spl_recursive_it_object*)iter->data, ((spl_recursive_it_iterator*)iter)->zobject TSRMLS_CC);
     408              61 : }
     409                 : 
     410              61 : static zend_object_iterator *spl_recursive_it_get_iterator(zend_class_entry *ce, zval *zobject, int by_ref TSRMLS_DC)
     411                 : {
     412                 :         spl_recursive_it_iterator *iterator;
     413                 :         spl_recursive_it_object   *object;
     414                 : 
     415              61 :         if (by_ref) {
     416               1 :                 zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
     417                 :         }
     418              60 :         iterator = emalloc(sizeof(spl_recursive_it_iterator));
     419              60 :         object   = (spl_recursive_it_object*)zend_object_store_get_object(zobject TSRMLS_CC);
     420              60 :         if (object->iterators == NULL) {
     421               0 :                 zend_error(E_ERROR, "The object to be iterated is in an invalid state: "
     422                 :                                 "the parent constructor has not been called");
     423                 :         }
     424                 : 
     425                 :         Z_ADDREF_P(zobject);
     426              60 :         iterator->intern.data = (void*)object;
     427              60 :         iterator->intern.funcs = ce->iterator_funcs.funcs;
     428              60 :         iterator->zobject = zobject;
     429              60 :         return (zend_object_iterator*)iterator;
     430                 : }
     431                 : 
     432                 : zend_object_iterator_funcs spl_recursive_it_iterator_funcs = {
     433                 :         spl_recursive_it_dtor,
     434                 :         spl_recursive_it_valid,
     435                 :         spl_recursive_it_get_current_data,
     436                 :         spl_recursive_it_get_current_key,
     437                 :         spl_recursive_it_move_forward,
     438                 :         spl_recursive_it_rewind
     439                 : };
     440                 : 
     441             120 : static void spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce_base, zend_class_entry *ce_inner, recursive_it_it_type rit_type)
     442                 : {
     443             120 :         zval                      *object = getThis();
     444                 :         spl_recursive_it_object   *intern;
     445                 :         zval                      *iterator;
     446                 :         zend_class_entry          *ce_iterator;
     447                 :         long                       mode, flags;
     448             120 :         int                        inc_refcount = 1;
     449                 :         zend_error_handling        error_handling;
     450                 : 
     451             120 :         zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling TSRMLS_CC);
     452                 : 
     453             120 :         switch(rit_type) {
     454                 :                 case RIT_RecursiveTreeIterator: {
     455                 : 
     456              24 :                         zval *caching_it, *caching_it_flags, *user_caching_it_flags = NULL;
     457              24 :                         mode = RIT_SELF_FIRST;
     458              24 :                         flags = RTIT_BYPASS_KEY;
     459                 : 
     460              24 :                         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "o|lzl", &iterator, &flags, &user_caching_it_flags, &mode) == SUCCESS) {
     461              23 :                                 if (instanceof_function(Z_OBJCE_P(iterator), zend_ce_aggregate TSRMLS_CC)) {
     462               6 :                                         zval *aggregate = iterator;
     463               6 :                                         zend_call_method_with_0_params(&aggregate, Z_OBJCE_P(aggregate), &Z_OBJCE_P(aggregate)->iterator_funcs.zf_new_iterator, "getiterator", &iterator);
     464               6 :                                         inc_refcount = 0;
     465                 :                                 }
     466                 : 
     467              23 :                                 MAKE_STD_ZVAL(caching_it_flags);
     468              23 :                                 if (user_caching_it_flags) {
     469               8 :                                         ZVAL_ZVAL(caching_it_flags, user_caching_it_flags, 1, 0);
     470                 :                                 } else {
     471              21 :                                         ZVAL_LONG(caching_it_flags, CIT_CATCH_GET_CHILD);
     472                 :                                 }
     473              23 :                                 spl_instantiate_arg_ex2(spl_ce_RecursiveCachingIterator, &caching_it, 1, iterator, caching_it_flags TSRMLS_CC);
     474              23 :                                 zval_ptr_dtor(&caching_it_flags);
     475              23 :                                 if (inc_refcount == 0 && iterator) {
     476               6 :                                         zval_ptr_dtor(&iterator);
     477                 :                                 }
     478              23 :                                 iterator = caching_it;
     479              23 :                                 inc_refcount = 0;
     480                 :                         } else {
     481               1 :                                 iterator = NULL;
     482                 :                         }
     483              24 :                         break;
     484                 :                 }
     485                 :                 case RIT_RecursiveIteratorIterator:
     486                 :                 default: {
     487              96 :                         mode = RIT_LEAVES_ONLY;
     488              96 :                         flags = 0;
     489                 : 
     490              96 :                         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "o|ll", &iterator, &mode, &flags) == SUCCESS) {
     491              95 :                                 if (instanceof_function(Z_OBJCE_P(iterator), zend_ce_aggregate TSRMLS_CC)) {
     492               5 :                                         zval *aggregate = iterator;
     493               5 :                                         zend_call_method_with_0_params(&aggregate, Z_OBJCE_P(aggregate), &Z_OBJCE_P(aggregate)->iterator_funcs.zf_new_iterator, "getiterator", &iterator);
     494               5 :                                         inc_refcount = 0;
     495                 :                                 }
     496                 :                         } else {
     497               1 :                                 iterator = NULL;
     498                 :                         }
     499                 :                         break;
     500                 :                 }
     501                 :         }
     502             120 :         if (!iterator || !instanceof_function(Z_OBJCE_P(iterator), spl_ce_RecursiveIterator TSRMLS_CC)) {
     503               3 :                 if (iterator && !inc_refcount) {
     504               1 :                         zval_ptr_dtor(&iterator);
     505                 :                 }
     506               3 :                 zend_throw_exception(spl_ce_InvalidArgumentException, "An instance of RecursiveIterator or IteratorAggregate creating it is required", 0 TSRMLS_CC);
     507               3 :                 zend_restore_error_handling(&error_handling TSRMLS_CC);
     508               3 :                 return;
     509                 :         }
     510                 : 
     511             117 :         intern = (spl_recursive_it_object*)zend_object_store_get_object(object TSRMLS_CC);
     512             117 :         intern->iterators = emalloc(sizeof(spl_sub_iterator));
     513             117 :         intern->level = 0;
     514             117 :         intern->mode = mode;
     515             117 :         intern->flags = flags;
     516             117 :         intern->max_depth = -1;
     517             117 :         intern->in_iteration = 0;
     518             117 :         intern->ce = Z_OBJCE_P(object);
     519                 : 
     520             117 :         zend_hash_find(&intern->ce->function_table, "beginiteration", sizeof("beginiteration"), (void **) &intern->beginIteration);
     521             117 :         if (intern->beginIteration->common.scope == ce_base) {
     522             115 :                 intern->beginIteration = NULL;
     523                 :         }
     524             117 :         zend_hash_find(&intern->ce->function_table, "enditeration", sizeof("enditeration"), (void **) &intern->endIteration);
     525             117 :         if (intern->endIteration->common.scope == ce_base) {
     526             115 :                 intern->endIteration = NULL;
     527                 :         }
     528             117 :         zend_hash_find(&intern->ce->function_table, "callhaschildren", sizeof("callHasChildren"), (void **) &intern->callHasChildren);
     529             117 :         if (intern->callHasChildren->common.scope == ce_base) {
     530             111 :                 intern->callHasChildren = NULL;
     531                 :         }
     532             117 :         zend_hash_find(&intern->ce->function_table, "callgetchildren", sizeof("callGetChildren"), (void **) &intern->callGetChildren);
     533             117 :         if (intern->callGetChildren->common.scope == ce_base) {
     534             115 :                 intern->callGetChildren = NULL;
     535                 :         }
     536             117 :         zend_hash_find(&intern->ce->function_table, "beginchildren", sizeof("beginchildren"), (void **) &intern->beginChildren);
     537             117 :         if (intern->beginChildren->common.scope == ce_base) {
     538             108 :                 intern->beginChildren = NULL;
     539                 :         }
     540             117 :         zend_hash_find(&intern->ce->function_table, "endchildren", sizeof("endchildren"), (void **) &intern->endChildren);
     541             117 :         if (intern->endChildren->common.scope == ce_base) {
     542              98 :                 intern->endChildren = NULL;
     543                 :         }
     544             117 :         zend_hash_find(&intern->ce->function_table, "nextelement", sizeof("nextElement"), (void **) &intern->nextElement);
     545             117 :         if (intern->nextElement->common.scope == ce_base) {
     546             113 :                 intern->nextElement = NULL;
     547                 :         }
     548             117 :         ce_iterator = Z_OBJCE_P(iterator); /* respect inheritance, don't use spl_ce_RecursiveIterator */
     549             117 :         intern->iterators[0].iterator = ce_iterator->get_iterator(ce_iterator, iterator, 0 TSRMLS_CC);
     550             117 :         if (inc_refcount) {
     551              90 :                 Z_ADDREF_P(iterator);
     552                 :         }
     553             117 :         intern->iterators[0].zobject = iterator;
     554             117 :         intern->iterators[0].ce = ce_iterator;
     555             117 :         intern->iterators[0].state = RS_START;
     556                 : 
     557             117 :         zend_restore_error_handling(&error_handling TSRMLS_CC);
     558                 : 
     559             117 :         if (EG(exception)) {
     560                 :                 zend_object_iterator *sub_iter;
     561                 : 
     562               3 :                 while (intern->level >= 0) {
     563               1 :                         sub_iter = intern->iterators[intern->level].iterator;
     564               1 :                         sub_iter->funcs->dtor(sub_iter TSRMLS_CC);
     565               1 :                         zval_ptr_dtor(&intern->iterators[intern->level--].zobject);
     566                 :                 }
     567               1 :                 efree(intern->iterators);
     568               1 :                 intern->iterators = NULL;
     569                 :         }
     570                 : }
     571                 : 
     572                 : /* {{{ proto void RecursiveIteratorIterator::__construct(RecursiveIterator|IteratorAggregate it [, int mode = RIT_LEAVES_ONLY [, int flags = 0]]) throws InvalidArgumentException
     573                 :    Creates a RecursiveIteratorIterator from a RecursiveIterator. */
     574              96 : SPL_METHOD(RecursiveIteratorIterator, __construct)
     575                 : {
     576              96 :         spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveIteratorIterator, zend_ce_iterator, RIT_RecursiveIteratorIterator);
     577              96 : } /* }}} */
     578                 : 
     579                 : /* {{{ proto void RecursiveIteratorIterator::rewind()
     580                 :    Rewind the iterator to the first element of the top level inner iterator. */
     581              54 : SPL_METHOD(RecursiveIteratorIterator, rewind)
     582                 : {
     583              54 :         spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
     584                 :         
     585              54 :         if (zend_parse_parameters_none() == FAILURE) {
     586               0 :                 return;
     587                 :         }
     588                 : 
     589              54 :         spl_recursive_it_rewind_ex(object, getThis() TSRMLS_CC);
     590                 : } /* }}} */
     591                 : 
     592                 : /* {{{ proto bool RecursiveIteratorIterator::valid()
     593                 :    Check whether the current position is valid */
     594             375 : SPL_METHOD(RecursiveIteratorIterator, valid)
     595                 : {
     596             375 :         spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
     597                 :         
     598             375 :         if (zend_parse_parameters_none() == FAILURE) {
     599               0 :                 return;
     600                 :         }
     601                 : 
     602             375 :         RETURN_BOOL(spl_recursive_it_valid_ex(object, getThis() TSRMLS_CC) == SUCCESS);
     603                 : } /* }}} */
     604                 : 
     605                 : /* {{{ proto mixed RecursiveIteratorIterator::key()
     606                 :    Access the current key */
     607              53 : SPL_METHOD(RecursiveIteratorIterator, key)
     608                 : {
     609              53 :         spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
     610              53 :         zend_object_iterator      *iterator = object->iterators[object->level].iterator;
     611                 :         
     612              53 :         if (zend_parse_parameters_none() == FAILURE) {
     613               0 :                 return;
     614                 :         }
     615                 : 
     616              53 :         if (iterator->funcs->get_current_key) {
     617                 :                 char *str_key;
     618                 :                 uint str_key_len;
     619                 :                 ulong int_key;
     620                 : 
     621              53 :                 switch (iterator->funcs->get_current_key(iterator, &str_key, &str_key_len, &int_key TSRMLS_CC)) {
     622                 :                         case HASH_KEY_IS_LONG:
     623              53 :                                 RETURN_LONG(int_key);
     624                 :                                 break;
     625                 :                         case HASH_KEY_IS_STRING:
     626               0 :                                 RETURN_STRINGL(str_key, str_key_len-1, 0);
     627                 :                                 break;
     628                 :                         default:
     629               0 :                                 RETURN_NULL();
     630                 :                 }
     631                 :         } else {
     632               0 :                 RETURN_NULL();
     633                 :         }
     634                 : } /* }}} */
     635                 : 
     636                 : /* {{{ proto mixed RecursiveIteratorIterator::current()
     637                 :    Access the current element value */
     638             125 : SPL_METHOD(RecursiveIteratorIterator, current)
     639                 : {
     640             125 :         spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
     641             125 :         zend_object_iterator      *iterator = object->iterators[object->level].iterator;
     642                 :         zval                      **data;
     643                 :         
     644             125 :         if (zend_parse_parameters_none() == FAILURE) {
     645               0 :                 return;
     646                 :         }
     647                 : 
     648             125 :         iterator->funcs->get_current_data(iterator, &data TSRMLS_CC);
     649             125 :         if (data && *data) {
     650             375 :                 RETURN_ZVAL(*data, 1, 0);
     651                 :         }
     652                 : } /* }}} */
     653                 : 
     654                 : /* {{{ proto void RecursiveIteratorIterator::next()
     655                 :    Move forward to the next element */
     656             344 : SPL_METHOD(RecursiveIteratorIterator, next)
     657                 : {
     658             344 :         spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
     659                 :         
     660             344 :         if (zend_parse_parameters_none() == FAILURE) {
     661               0 :                 return;
     662                 :         }
     663                 : 
     664             344 :         spl_recursive_it_move_forward_ex(object, getThis() TSRMLS_CC);
     665                 : } /* }}} */
     666                 : 
     667                 : /* {{{ proto int RecursiveIteratorIterator::getDepth()
     668                 :    Get the current depth of the recursive iteration */
     669             206 : SPL_METHOD(RecursiveIteratorIterator, getDepth)
     670                 : {
     671             206 :         spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
     672                 :         
     673             206 :         if (zend_parse_parameters_none() == FAILURE) {
     674               0 :                 return;
     675                 :         }
     676                 :         
     677             206 :         RETURN_LONG(object->level);
     678                 : } /* }}} */
     679                 : 
     680                 : /* {{{ proto RecursiveIterator RecursiveIteratorIterator::getSubIterator([int level])
     681                 :    The current active sub iterator or the iterator at specified level */
     682              15 : SPL_METHOD(RecursiveIteratorIterator, getSubIterator)
     683                 : {
     684              15 :         spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
     685              15 :         long  level = object->level;
     686                 :         
     687              15 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &level) == FAILURE) {
     688               1 :                 return;
     689                 :         }
     690              14 :         if (level < 0 || level > object->level) {
     691               2 :                 RETURN_NULL();
     692                 :         }
     693              36 :         RETURN_ZVAL(object->iterators[level].zobject, 1, 0);
     694                 : } /* }}} */
     695                 : 
     696                 : /* {{{ proto RecursiveIterator RecursiveIteratorIterator::getInnerIterator()
     697                 :    The current active sub iterator */
     698              57 : SPL_METHOD(RecursiveIteratorIterator, getInnerIterator)
     699                 : {
     700              57 :         spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
     701              57 :         long  level = object->level;
     702                 :         
     703              57 :         if (zend_parse_parameters_none() == FAILURE) {
     704               0 :                 return;
     705                 :         }
     706                 :         
     707             171 :         RETURN_ZVAL(object->iterators[level].zobject, 1, 0);
     708                 : } /* }}} */
     709                 : 
     710                 : /* {{{ proto RecursiveIterator RecursiveIteratorIterator::beginIteration()
     711                 :    Called when iteration begins (after first rewind() call) */
     712               1 : SPL_METHOD(RecursiveIteratorIterator, beginIteration)
     713                 : {
     714               1 :         if (zend_parse_parameters_none() == FAILURE) {
     715               0 :                 return;
     716                 :         }
     717                 :         /* nothing to do */
     718                 : } /* }}} */
     719                 : 
     720                 : /* {{{ proto RecursiveIterator RecursiveIteratorIterator::endIteration()
     721                 :    Called when iteration ends (when valid() first returns false */
     722               1 : SPL_METHOD(RecursiveIteratorIterator, endIteration)
     723                 : {
     724               1 :         if (zend_parse_parameters_none() == FAILURE) {
     725               0 :                 return;
     726                 :         }
     727                 :         /* nothing to do */
     728                 : } /* }}} */
     729                 : 
     730                 : /* {{{ proto bool RecursiveIteratorIterator::callHasChildren()
     731                 :    Called for each element to test whether it has children */
     732              43 : SPL_METHOD(RecursiveIteratorIterator, callHasChildren)
     733                 : {
     734              43 :         spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
     735              43 :         zend_class_entry *ce = object->iterators[object->level].ce;
     736                 :         zval *retval, *zobject;
     737                 :         
     738              43 :         if (zend_parse_parameters_none() == FAILURE) {
     739               0 :                 return;
     740                 :         }
     741                 : 
     742              43 :         zobject = object->iterators[object->level].zobject;
     743              43 :         if (!zobject) {
     744               0 :                 RETURN_FALSE;
     745                 :         } else {
     746              43 :                 zend_call_method_with_0_params(&zobject, ce, NULL, "haschildren", &retval);
     747              43 :                 if (retval) {
     748             129 :                         RETURN_ZVAL(retval, 0, 1);
     749                 :                 } else {
     750               0 :                         RETURN_FALSE;
     751                 :                 }
     752                 :         }
     753                 : } /* }}} */
     754                 : 
     755                 : /* {{{ proto RecursiveIterator RecursiveIteratorIterator::callGetChildren()
     756                 :    Return children of current element */
     757               1 : SPL_METHOD(RecursiveIteratorIterator, callGetChildren)
     758                 : {
     759               1 :         spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
     760               1 :         zend_class_entry *ce = object->iterators[object->level].ce;
     761                 :         zval *retval, *zobject;
     762                 :         
     763               1 :         if (zend_parse_parameters_none() == FAILURE) {
     764               0 :                 return;
     765                 :         }
     766                 : 
     767               1 :         zobject = object->iterators[object->level].zobject;
     768               1 :         if (!zobject) {
     769               0 :                 return;
     770                 :         } else {
     771               1 :                 zend_call_method_with_0_params(&zobject, ce, NULL, "getchildren", &retval);
     772               1 :                 if (retval) {
     773               0 :                         RETURN_ZVAL(retval, 0, 1);
     774                 :                 }
     775                 :         }
     776                 : } /* }}} */
     777                 : 
     778                 : /* {{{ proto void RecursiveIteratorIterator::beginChildren()
     779                 :    Called when recursing one level down */
     780               3 : SPL_METHOD(RecursiveIteratorIterator, beginChildren)
     781                 : {
     782               3 :         if (zend_parse_parameters_none() == FAILURE) {
     783               0 :                 return;
     784                 :         }
     785                 :         /* nothing to do */
     786                 : } /* }}} */
     787                 : 
     788                 : /* {{{ proto void RecursiveIteratorIterator::endChildren()
     789                 :    Called when end recursing one level */
     790               3 : SPL_METHOD(RecursiveIteratorIterator, endChildren)
     791                 : {
     792               3 :         if (zend_parse_parameters_none() == FAILURE) {
     793               0 :                 return;
     794                 :         }
     795                 :         /* nothing to do */
     796                 : } /* }}} */
     797                 : 
     798                 : /* {{{ proto void RecursiveIteratorIterator::nextElement()
     799                 :    Called when the next element is available */
     800               1 : SPL_METHOD(RecursiveIteratorIterator, nextElement)
     801                 : {
     802               1 :         if (zend_parse_parameters_none() == FAILURE) {
     803               0 :                 return;
     804                 :         }
     805                 :         /* nothing to do */
     806                 : } /* }}} */
     807                 : 
     808                 : /* {{{ proto void RecursiveIteratorIterator::setMaxDepth([$max_depth = -1])
     809                 :    Set the maximum allowed depth (or any depth if pmax_depth = -1] */
     810              12 : SPL_METHOD(RecursiveIteratorIterator, setMaxDepth)
     811                 : {
     812              12 :         spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
     813              12 :         long  max_depth = -1;
     814                 :         
     815              12 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &max_depth) == FAILURE) {
     816               2 :                 return;
     817                 :         }
     818              10 :         if (max_depth < -1) {
     819               1 :                 zend_throw_exception(spl_ce_OutOfRangeException, "Parameter max_depth must be >= -1", 0 TSRMLS_CC);
     820               1 :                 return;
     821                 :         }
     822               9 :         object->max_depth = max_depth;
     823                 : } /* }}} */
     824                 : 
     825                 : /* {{{ proto int|false RecursiveIteratorIterator::getMaxDepth()
     826                 :    Return the maximum accepted depth or false if any depth is allowed */
     827               8 : SPL_METHOD(RecursiveIteratorIterator, getMaxDepth)
     828                 : {
     829               8 :         spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
     830                 : 
     831               8 :         if (zend_parse_parameters_none() == FAILURE) {
     832               0 :                 return;
     833                 :         }
     834                 :         
     835               8 :         if (object->max_depth == -1) {
     836               3 :                 RETURN_FALSE;
     837                 :         } else {
     838               5 :                 RETURN_LONG(object->max_depth);
     839                 :         }
     840                 : } /* }}} */
     841                 : 
     842             506 : static union _zend_function *spl_recursive_it_get_method(zval **object_ptr, char *method, int method_len TSRMLS_DC)
     843                 : {
     844                 :         union _zend_function    *function_handler;
     845             506 :         spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(*object_ptr TSRMLS_CC);
     846             506 :         long                     level = object->level;
     847                 :         zval                    *zobj;
     848                 : 
     849             506 :         if (!object->iterators) {
     850               1 :                 php_error_docref(NULL TSRMLS_CC, E_ERROR, "The %s instance wasn't initialized properly", Z_OBJCE_PP(object_ptr)->name);
     851                 :         }
     852             505 :         zobj = object->iterators[level].zobject;
     853                 : 
     854             505 :         function_handler = std_object_handlers.get_method(object_ptr, method, method_len TSRMLS_CC);
     855             505 :         if (!function_handler) {
     856              20 :                 if (zend_hash_find(&Z_OBJCE_P(zobj)->function_table, method, method_len+1, (void **) &function_handler) == FAILURE) {
     857              20 :                         if (Z_OBJ_HT_P(zobj)->get_method) {
     858              20 :                                 *object_ptr = zobj;
     859              20 :                                 function_handler = Z_OBJ_HT_P(*object_ptr)->get_method(object_ptr, method, method_len TSRMLS_CC);
     860                 :                         }
     861                 :                 }
     862                 :         }
     863             505 :         return function_handler;
     864                 : }
     865                 : 
     866                 : /* {{{ spl_RecursiveIteratorIterator_dtor */
     867             108 : static void spl_RecursiveIteratorIterator_dtor(zend_object *_object, zend_object_handle handle TSRMLS_DC)
     868                 : {
     869             108 :         spl_recursive_it_object   *object = (spl_recursive_it_object *)_object;
     870                 :         zend_object_iterator      *sub_iter;
     871                 : 
     872                 :         /* call standard dtor */
     873             108 :         zend_objects_destroy_object(_object, handle TSRMLS_CC);
     874                 : 
     875             108 :         if (object->iterators) {
     876             328 :                 while (object->level >= 0) {
     877             112 :                         sub_iter = object->iterators[object->level].iterator;
     878             112 :                         sub_iter->funcs->dtor(sub_iter TSRMLS_CC);
     879             112 :                         zval_ptr_dtor(&object->iterators[object->level--].zobject);
     880                 :                 }
     881             108 :                 efree(object->iterators);
     882             108 :                 object->iterators = NULL;
     883                 :         }
     884             108 : }
     885                 : /* }}} */
     886                 : 
     887                 : /* {{{ spl_RecursiveIteratorIterator_dtor */
     888             122 : static void spl_RecursiveIteratorIterator_free_storage(void *_object TSRMLS_DC)
     889                 : {
     890             122 :         spl_recursive_it_object   *object = (spl_recursive_it_object *)_object;
     891                 : 
     892             122 :         zend_object_std_dtor(&object->std TSRMLS_CC);
     893             122 :         smart_str_free(&object->prefix[0]);
     894             122 :         smart_str_free(&object->prefix[1]);
     895             122 :         smart_str_free(&object->prefix[2]);
     896             122 :         smart_str_free(&object->prefix[3]);
     897             122 :         smart_str_free(&object->prefix[4]);
     898             122 :         smart_str_free(&object->prefix[5]);
     899                 : 
     900             122 :         efree(object);
     901             122 : }
     902                 : /* }}} */
     903                 : 
     904                 : /* {{{ spl_RecursiveIteratorIterator_new_ex */
     905             122 : static zend_object_value spl_RecursiveIteratorIterator_new_ex(zend_class_entry *class_type, int init_prefix TSRMLS_DC)
     906                 : {
     907                 :         zend_object_value retval;
     908                 :         spl_recursive_it_object *intern;
     909                 :         zval *tmp;
     910                 : 
     911             122 :         intern = emalloc(sizeof(spl_recursive_it_object));
     912             122 :         memset(intern, 0, sizeof(spl_recursive_it_object));
     913                 : 
     914             122 :         if (init_prefix) {
     915              24 :                 smart_str_appendl(&intern->prefix[0], "",    0);
     916              24 :                 smart_str_appendl(&intern->prefix[1], "| ",  2);
     917              24 :                 smart_str_appendl(&intern->prefix[2], "  ",  2);
     918              24 :                 smart_str_appendl(&intern->prefix[3], "|-",  2);
     919              24 :                 smart_str_appendl(&intern->prefix[4], "\\-", 2);
     920              24 :                 smart_str_appendl(&intern->prefix[5], "",    0);
     921                 :         }
     922                 : 
     923             122 :         zend_object_std_init(&intern->std, class_type TSRMLS_CC);
     924             122 :         zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
     925                 : 
     926             122 :         retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)spl_RecursiveIteratorIterator_dtor, (zend_objects_free_object_storage_t) spl_RecursiveIteratorIterator_free_storage, NULL TSRMLS_CC);
     927             122 :         retval.handlers = &spl_handlers_rec_it_it;
     928             122 :         return retval;
     929                 : }
     930                 : /* }}} */
     931                 : 
     932                 : /* {{{ spl_RecursiveIteratorIterator_new */
     933              98 : static zend_object_value spl_RecursiveIteratorIterator_new(zend_class_entry *class_type TSRMLS_DC)
     934                 : {
     935              98 :         return spl_RecursiveIteratorIterator_new_ex(class_type, 0 TSRMLS_CC);
     936                 : }
     937                 : /* }}} */
     938                 : 
     939                 : /* {{{ spl_RecursiveTreeIterator_new */
     940              24 : static zend_object_value spl_RecursiveTreeIterator_new(zend_class_entry *class_type TSRMLS_DC)
     941                 : {
     942              24 :         return spl_RecursiveIteratorIterator_new_ex(class_type, 1 TSRMLS_CC);
     943                 : }
     944                 : /* }}} */
     945                 : 
     946                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_it___construct, 0, 0, 1) 
     947                 :         ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
     948                 :         ZEND_ARG_INFO(0, mode)
     949                 :         ZEND_ARG_INFO(0, flags)
     950                 : ZEND_END_ARG_INFO();
     951                 : 
     952                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_it_getSubIterator, 0, 0, 0)
     953                 :         ZEND_ARG_INFO(0, level)
     954                 : ZEND_END_ARG_INFO();
     955                 : 
     956                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_it_setMaxDepth, 0, 0, 0)
     957                 :         ZEND_ARG_INFO(0, max_depth)
     958                 : ZEND_END_ARG_INFO();
     959                 : 
     960                 : static const zend_function_entry spl_funcs_RecursiveIteratorIterator[] = {
     961                 :         SPL_ME(RecursiveIteratorIterator, __construct,       arginfo_recursive_it___construct,    ZEND_ACC_PUBLIC)
     962                 :         SPL_ME(RecursiveIteratorIterator, rewind,            arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
     963                 :         SPL_ME(RecursiveIteratorIterator, valid,             arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
     964                 :         SPL_ME(RecursiveIteratorIterator, key,               arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
     965                 :         SPL_ME(RecursiveIteratorIterator, current,           arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
     966                 :         SPL_ME(RecursiveIteratorIterator, next,              arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
     967                 :         SPL_ME(RecursiveIteratorIterator, getDepth,          arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
     968                 :         SPL_ME(RecursiveIteratorIterator, getSubIterator,    arginfo_recursive_it_getSubIterator, ZEND_ACC_PUBLIC)
     969                 :         SPL_ME(RecursiveIteratorIterator, getInnerIterator,  arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
     970                 :         SPL_ME(RecursiveIteratorIterator, beginIteration,    arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
     971                 :         SPL_ME(RecursiveIteratorIterator, endIteration,      arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
     972                 :         SPL_ME(RecursiveIteratorIterator, callHasChildren,   arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
     973                 :         SPL_ME(RecursiveIteratorIterator, callGetChildren,   arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
     974                 :         SPL_ME(RecursiveIteratorIterator, beginChildren,     arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
     975                 :         SPL_ME(RecursiveIteratorIterator, endChildren,       arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
     976                 :         SPL_ME(RecursiveIteratorIterator, nextElement,       arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
     977                 :         SPL_ME(RecursiveIteratorIterator, setMaxDepth,       arginfo_recursive_it_setMaxDepth,    ZEND_ACC_PUBLIC)
     978                 :         SPL_ME(RecursiveIteratorIterator, getMaxDepth,       arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
     979                 :         PHP_FE_END
     980                 : };
     981                 : 
     982             307 : static void spl_recursive_tree_iterator_get_prefix(spl_recursive_it_object *object, zval *return_value TSRMLS_DC)
     983                 : {
     984             307 :         smart_str  str = {0};
     985                 :         zval      *has_next;
     986                 :         int        level;
     987                 : 
     988             307 :         smart_str_appendl(&str, object->prefix[0].c, object->prefix[0].len);
     989                 :         
     990             609 :         for (level = 0; level < object->level; ++level) {
     991             302 :                 zend_call_method_with_0_params(&object->iterators[level].zobject, object->iterators[level].ce, NULL, "hasnext", &has_next);
     992             302 :                 if (has_next) {
     993             302 :                         if (Z_LVAL_P(has_next)) {
     994             105 :                                 smart_str_appendl(&str, object->prefix[1].c, object->prefix[1].len);
     995                 :                         } else {
     996             197 :                                 smart_str_appendl(&str, object->prefix[2].c, object->prefix[2].len);
     997                 :                         }
     998             302 :                         zval_ptr_dtor(&has_next);
     999                 :                 }
    1000                 :         }
    1001             307 :         zend_call_method_with_0_params(&object->iterators[level].zobject, object->iterators[level].ce, NULL, "hasnext", &has_next);
    1002             307 :         if (has_next) {
    1003             307 :                 if (Z_LVAL_P(has_next)) {
    1004             183 :                         smart_str_appendl(&str, object->prefix[3].c, object->prefix[3].len);
    1005                 :                 } else {
    1006             124 :                         smart_str_appendl(&str, object->prefix[4].c, object->prefix[4].len);
    1007                 :                 }
    1008             307 :                 zval_ptr_dtor(&has_next);
    1009                 :         }
    1010                 : 
    1011             307 :         smart_str_appendl(&str, object->prefix[5].c, object->prefix[5].len);
    1012             307 :         smart_str_0(&str);
    1013                 : 
    1014             307 :         RETVAL_STRINGL(str.c, str.len, 0);
    1015             307 : }
    1016                 : 
    1017             214 : static void spl_recursive_tree_iterator_get_entry(spl_recursive_it_object * object, zval * return_value TSRMLS_DC)
    1018                 : {
    1019             214 :         zend_object_iterator      *iterator = object->iterators[object->level].iterator;
    1020                 :         zval                     **data;
    1021                 :         zend_error_handling        error_handling;
    1022                 : 
    1023             214 :         iterator->funcs->get_current_data(iterator, &data TSRMLS_CC);
    1024                 : 
    1025             214 :         zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling TSRMLS_CC);
    1026             214 :         if (data && *data) {
    1027             428 :                 RETVAL_ZVAL(*data, 1, 0);
    1028                 :         }
    1029             214 :         if (Z_TYPE_P(return_value) == IS_ARRAY) {
    1030              64 :                 zval_dtor(return_value);
    1031              64 :                 ZVAL_STRINGL(return_value, "Array", sizeof("Array")-1, 1);
    1032                 :         } else {
    1033             150 :                 convert_to_string(return_value);
    1034                 :         }
    1035             214 :         zend_restore_error_handling(&error_handling TSRMLS_CC);
    1036             214 : }
    1037                 : 
    1038             307 : static void spl_recursive_tree_iterator_get_postfix(spl_recursive_it_object * object, zval * return_value TSRMLS_DC)
    1039                 : {
    1040             307 :         RETVAL_STRINGL("", 0, 1);
    1041             307 : }
    1042                 : 
    1043                 : /* {{{ proto void RecursiveTreeIterator::__construct(RecursiveIterator|IteratorAggregate it [, int flags = RTIT_BYPASS_KEY [, int cit_flags = CIT_CATCH_GET_CHILD [, mode = RIT_SELF_FIRST ]]]) throws InvalidArgumentException
    1044                 :    RecursiveIteratorIterator to generate ASCII graphic trees for the entries in a RecursiveIterator */
    1045              24 : SPL_METHOD(RecursiveTreeIterator, __construct)
    1046                 : {
    1047              24 :         spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveTreeIterator, zend_ce_iterator, RIT_RecursiveTreeIterator);
    1048              24 : } /* }}} */
    1049                 : 
    1050                 : /* {{{ proto void RecursiveTreeIterator::setPrefixPart(int part, string prefix) throws OutOfRangeException
    1051                 :    Sets prefix parts as used in getPrefix() */
    1052              11 : SPL_METHOD(RecursiveTreeIterator, setPrefixPart)
    1053                 : {
    1054              11 :         spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
    1055                 :         long  part;
    1056                 :         char* prefix;
    1057                 :         int   prefix_len;
    1058                 :         
    1059              11 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &part, &prefix, &prefix_len) == FAILURE) {
    1060               3 :                 return;
    1061                 :         }
    1062               8 :         if (0 > part || part > 5) {
    1063               2 :                 zend_throw_exception_ex(spl_ce_OutOfRangeException, 0 TSRMLS_CC, "Use RecursiveTreeIterator::PREFIX_* constant");
    1064               2 :                 return;
    1065                 :         }
    1066                 :         
    1067               6 :         smart_str_free(&object->prefix[part]);
    1068               6 :         smart_str_appendl(&object->prefix[part], prefix, prefix_len);
    1069                 : } /* }}} */
    1070                 : 
    1071                 : /* {{{ proto string RecursiveTreeIterator::getPrefix()
    1072                 :    Returns the string to place in front of current element */
    1073               9 : SPL_METHOD(RecursiveTreeIterator, getPrefix)
    1074                 : {
    1075               9 :         spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
    1076                 : 
    1077               9 :         if (zend_parse_parameters_none() == FAILURE) {
    1078               0 :                 return;
    1079                 :         }
    1080               9 :         spl_recursive_tree_iterator_get_prefix(object, return_value TSRMLS_CC);
    1081                 : } /* }}} */
    1082                 : 
    1083                 : /* {{{ proto string RecursiveTreeIterator::getEntry()
    1084                 :    Returns the string presentation built for current element */
    1085              22 : SPL_METHOD(RecursiveTreeIterator, getEntry)
    1086                 : {
    1087              22 :         spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
    1088                 : 
    1089              22 :         if (zend_parse_parameters_none() == FAILURE) {
    1090               0 :                 return;
    1091                 :         }
    1092                 :         
    1093              22 :         spl_recursive_tree_iterator_get_entry(object, return_value TSRMLS_CC);
    1094                 : } /* }}} */
    1095                 : 
    1096                 : /* {{{ proto string RecursiveTreeIterator::getPostfix()
    1097                 :    Returns the string to place after the current element */
    1098               9 : SPL_METHOD(RecursiveTreeIterator, getPostfix)
    1099                 : {
    1100               9 :         spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
    1101                 : 
    1102               9 :         if (zend_parse_parameters_none() == FAILURE) {
    1103               0 :                 return;
    1104                 :         }
    1105                 :         
    1106               9 :         spl_recursive_tree_iterator_get_postfix(object, return_value TSRMLS_CC);
    1107                 : } /* }}} */
    1108                 : 
    1109                 : /* {{{ proto mixed RecursiveTreeIterator::current()
    1110                 :    Returns the current element prefixed and postfixed */
    1111             228 : SPL_METHOD(RecursiveTreeIterator, current)
    1112                 : {
    1113             228 :         spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
    1114                 :         zval                       prefix, entry, postfix;
    1115                 :         char                      *str, *ptr;
    1116                 :         size_t                     str_len;
    1117                 :         
    1118             228 :         if (zend_parse_parameters_none() == FAILURE) {
    1119               0 :                 return;
    1120                 :         }
    1121                 : 
    1122             228 :         if (object->flags & RTIT_BYPASS_CURRENT) {
    1123              36 :                 zend_object_iterator      *iterator = object->iterators[object->level].iterator;
    1124                 :                 zval                      **data;
    1125                 : 
    1126              36 :                 iterator->funcs->get_current_data(iterator, &data TSRMLS_CC);
    1127              36 :                 if (data && *data) {
    1128             108 :                         RETURN_ZVAL(*data, 1, 0);
    1129                 :                 } else {
    1130               0 :                         RETURN_NULL();
    1131                 :                 }
    1132                 :         }
    1133                 : 
    1134             192 :         spl_recursive_tree_iterator_get_prefix(object, &prefix TSRMLS_CC);
    1135             192 :         spl_recursive_tree_iterator_get_entry(object, &entry TSRMLS_CC);
    1136             192 :         spl_recursive_tree_iterator_get_postfix(object, &postfix TSRMLS_CC);
    1137                 : 
    1138             192 :         str_len = Z_STRLEN(prefix) + Z_STRLEN(entry) + Z_STRLEN(postfix);
    1139             192 :         str = (char *) emalloc(str_len + 1U);
    1140             192 :         ptr = str;
    1141                 : 
    1142             192 :         memcpy(ptr, Z_STRVAL(prefix), Z_STRLEN(prefix));
    1143             192 :         ptr += Z_STRLEN(prefix);
    1144             192 :         memcpy(ptr, Z_STRVAL(entry), Z_STRLEN(entry));
    1145             192 :         ptr += Z_STRLEN(entry);
    1146             192 :         memcpy(ptr, Z_STRVAL(postfix), Z_STRLEN(postfix));
    1147             192 :         ptr += Z_STRLEN(postfix);
    1148             192 :         *ptr = 0;
    1149                 : 
    1150             192 :         zval_dtor(&prefix);
    1151             192 :         zval_dtor(&entry);
    1152             192 :         zval_dtor(&postfix);
    1153                 : 
    1154             192 :         RETURN_STRINGL(str, str_len, 0);
    1155                 : } /* }}} */
    1156                 : 
    1157                 : /* {{{ proto mixed RecursiveTreeIterator::key()
    1158                 :    Returns the current key prefixed and postfixed */
    1159             236 : SPL_METHOD(RecursiveTreeIterator, key)
    1160                 : {
    1161             236 :         spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
    1162             236 :         zend_object_iterator      *iterator = object->iterators[object->level].iterator;
    1163                 :         zval                       prefix, key, postfix, key_copy;
    1164                 :         char                      *str, *ptr;
    1165                 :         size_t                     str_len;
    1166                 :         
    1167             236 :         if (zend_parse_parameters_none() == FAILURE) {
    1168               0 :                 return;
    1169                 :         }
    1170                 : 
    1171             236 :         if (iterator->funcs->get_current_key) {
    1172                 :                 char *str_key;
    1173                 :                 uint str_key_len;
    1174                 :                 ulong int_key;
    1175                 : 
    1176             236 :                 switch (iterator->funcs->get_current_key(iterator, &str_key, &str_key_len, &int_key TSRMLS_CC)) {
    1177                 :                         case HASH_KEY_IS_LONG:
    1178             160 :                                 ZVAL_LONG(&key, int_key);
    1179             160 :                                 break;
    1180                 :                         case HASH_KEY_IS_STRING:
    1181              76 :                                 ZVAL_STRINGL(&key, str_key, str_key_len-1, 0);
    1182              76 :                                 break;
    1183                 :                         default:
    1184               0 :                                 ZVAL_NULL(&key);
    1185                 :                 }
    1186                 :         } else {
    1187               0 :                 ZVAL_NULL(&key);
    1188                 :         }
    1189                 : 
    1190             236 :         if (object->flags & RTIT_BYPASS_KEY) {
    1191             130 :                 zval *key_ptr = &key;
    1192             260 :                 RETVAL_ZVAL(key_ptr, 1, 0);
    1193             130 :                 zval_dtor(&key);
    1194             130 :                 return;
    1195                 :         }
    1196                 : 
    1197             106 :         if (Z_TYPE(key) != IS_STRING) {
    1198                 :                 int use_copy;
    1199              92 :                 zend_make_printable_zval(&key, &key_copy, &use_copy);
    1200              92 :                 if (use_copy) {
    1201              92 :                         key = key_copy;
    1202                 :                 }
    1203                 :         }
    1204                 : 
    1205             106 :         spl_recursive_tree_iterator_get_prefix(object, &prefix TSRMLS_CC);
    1206             106 :         spl_recursive_tree_iterator_get_postfix(object, &postfix TSRMLS_CC);
    1207                 : 
    1208             106 :         str_len = Z_STRLEN(prefix) + Z_STRLEN(key) + Z_STRLEN(postfix);
    1209             106 :         str = (char *) emalloc(str_len + 1U);
    1210             106 :         ptr = str;
    1211                 : 
    1212             106 :         memcpy(ptr, Z_STRVAL(prefix), Z_STRLEN(prefix));
    1213             106 :         ptr += Z_STRLEN(prefix);
    1214             106 :         memcpy(ptr, Z_STRVAL(key), Z_STRLEN(key));
    1215             106 :         ptr += Z_STRLEN(key);
    1216             106 :         memcpy(ptr, Z_STRVAL(postfix), Z_STRLEN(postfix));
    1217             106 :         ptr += Z_STRLEN(postfix);
    1218             106 :         *ptr = 0;
    1219                 : 
    1220             106 :         zval_dtor(&prefix);
    1221             106 :         zval_dtor(&key);
    1222             106 :         zval_dtor(&postfix);
    1223                 : 
    1224             106 :         RETVAL_STRINGL(str, str_len, 0);
    1225                 : } /* }}} */
    1226                 : 
    1227                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_tree_it___construct, 0, 0, 1) 
    1228                 :         ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
    1229                 :         ZEND_ARG_INFO(0, flags)
    1230                 :         ZEND_ARG_INFO(0, caching_it_flags)
    1231                 :         ZEND_ARG_INFO(0, mode)
    1232                 : ZEND_END_ARG_INFO();
    1233                 : 
    1234                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_tree_it_setPrefixPart, 0, 0, 2)
    1235                 :         ZEND_ARG_INFO(0, part)
    1236                 :         ZEND_ARG_INFO(0, value)
    1237                 : ZEND_END_ARG_INFO();
    1238                 : 
    1239                 : static const zend_function_entry spl_funcs_RecursiveTreeIterator[] = {
    1240                 :         SPL_ME(RecursiveTreeIterator,     __construct,       arginfo_recursive_tree_it___construct,   ZEND_ACC_PUBLIC)
    1241                 :         SPL_ME(RecursiveIteratorIterator, rewind,            arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
    1242                 :         SPL_ME(RecursiveIteratorIterator, valid,             arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
    1243                 :         SPL_ME(RecursiveTreeIterator,     key,               arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
    1244                 :         SPL_ME(RecursiveTreeIterator,     current,           arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
    1245                 :         SPL_ME(RecursiveIteratorIterator, next,              arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
    1246                 :         SPL_ME(RecursiveIteratorIterator, beginIteration,    arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
    1247                 :         SPL_ME(RecursiveIteratorIterator, endIteration,      arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
    1248                 :         SPL_ME(RecursiveIteratorIterator, callHasChildren,   arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
    1249                 :         SPL_ME(RecursiveIteratorIterator, callGetChildren,   arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
    1250                 :         SPL_ME(RecursiveIteratorIterator, beginChildren,     arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
    1251                 :         SPL_ME(RecursiveIteratorIterator, endChildren,       arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
    1252                 :         SPL_ME(RecursiveIteratorIterator, nextElement,       arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
    1253                 :         SPL_ME(RecursiveTreeIterator,     getPrefix,         arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
    1254                 :         SPL_ME(RecursiveTreeIterator,     setPrefixPart,     arginfo_recursive_tree_it_setPrefixPart, ZEND_ACC_PUBLIC)
    1255                 :         SPL_ME(RecursiveTreeIterator,     getEntry,          arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
    1256                 :         SPL_ME(RecursiveTreeIterator,     getPostfix,        arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
    1257                 :         PHP_FE_END
    1258                 : };
    1259                 : 
    1260                 : #if MBO_0
    1261                 : static int spl_dual_it_gets_implemented(zend_class_entry *interface, zend_class_entry *class_type TSRMLS_DC)
    1262                 : {
    1263                 :         class_type->iterator_funcs.zf_valid = NULL;
    1264                 :         class_type->iterator_funcs.zf_current = NULL;
    1265                 :         class_type->iterator_funcs.zf_key = NULL;
    1266                 :         class_type->iterator_funcs.zf_next = NULL;
    1267                 :         class_type->iterator_funcs.zf_rewind = NULL;
    1268                 :         if (!class_type->iterator_funcs.funcs) {
    1269                 :                 class_type->iterator_funcs.funcs = &zend_interface_iterator_funcs_iterator;
    1270                 :         }
    1271                 : 
    1272                 :         return SUCCESS;
    1273                 : }
    1274                 : #endif
    1275                 : 
    1276             323 : static union _zend_function *spl_dual_it_get_method(zval **object_ptr, char *method, int method_len TSRMLS_DC)
    1277                 : {
    1278                 :         union _zend_function *function_handler;
    1279                 :         spl_dual_it_object   *intern;
    1280                 : 
    1281             323 :         intern = (spl_dual_it_object*)zend_object_store_get_object(*object_ptr TSRMLS_CC);
    1282                 : 
    1283             323 :         function_handler = std_object_handlers.get_method(object_ptr, method, method_len TSRMLS_CC);
    1284             323 :         if (!function_handler && intern->inner.ce) {
    1285              14 :                 if (zend_hash_find(&intern->inner.ce->function_table, method, method_len+1, (void **) &function_handler) == FAILURE) {
    1286              12 :                         if (Z_OBJ_HT_P(intern->inner.zobject)->get_method) {
    1287              12 :                                 *object_ptr = intern->inner.zobject;
    1288              12 :                                 function_handler = Z_OBJ_HT_P(*object_ptr)->get_method(object_ptr, method, method_len TSRMLS_CC);
    1289                 :                         }
    1290                 :                 }
    1291                 :         }
    1292             323 :         return function_handler;
    1293                 : }
    1294                 : 
    1295                 : #if MBO_0
    1296                 : int spl_dual_it_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
    1297                 : {
    1298                 :         zval ***func_params, func;
    1299                 :         zval *retval_ptr;
    1300                 :         int arg_count;
    1301                 :         int current = 0;
    1302                 :         int success;
    1303                 :         void **p;
    1304                 :         spl_dual_it_object   *intern;
    1305                 : 
    1306                 :         intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
    1307                 : 
    1308                 :         ZVAL_STRING(&func, method, 0);
    1309                 :         if (!zend_is_callable(&func, 0, &method TSRMLS_CC)) {
    1310                 :                 php_error_docref(NULL TSRMLS_CC, E_ERROR, "Method %s::%s() does not exist", intern->inner.ce->name, method);
    1311                 :                 return FAILURE;
    1312                 :         }
    1313                 : 
    1314                 :         p = EG(argument_stack).top_element-2;
    1315                 :         arg_count = (ulong) *p;
    1316                 : 
    1317                 :         func_params = safe_emalloc(sizeof(zval **), arg_count, 0);
    1318                 : 
    1319                 :         current = 0;
    1320                 :         while (arg_count-- > 0) {
    1321                 :                 func_params[current] = (zval **) p - (arg_count-current);
    1322                 :                 current++;
    1323                 :         }
    1324                 :         arg_count = current; /* restore */
    1325                 : 
    1326                 :         if (call_user_function_ex(EG(function_table), NULL, &func, &retval_ptr, arg_count, func_params, 0, NULL TSRMLS_CC) == SUCCESS && retval_ptr) {
    1327                 :                 RETURN_ZVAL(retval_ptr, 0, 1);
    1328                 :                 
    1329                 :                 success = SUCCESS;
    1330                 :         } else {
    1331                 :                 php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unable to call %s::%s()", intern->inner.ce->name, method);
    1332                 :                 success = FAILURE;
    1333                 :         }
    1334                 : 
    1335                 :         efree(func_params); 
    1336                 :         return success;
    1337                 : }
    1338                 : #endif
    1339                 : 
    1340                 : #define SPL_CHECK_CTOR(intern, classname) \
    1341                 :         if (intern->dit_type == DIT_Unknown) { \
    1342                 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Classes derived from %s must call %s::__construct()", \
    1343                 :                                 (spl_ce_##classname)->name, (spl_ce_##classname)->name); \
    1344                 :                 return; \
    1345                 :         }
    1346                 : 
    1347                 : #define APPENDIT_CHECK_CTOR(intern) SPL_CHECK_CTOR(intern, AppendIterator)
    1348                 : 
    1349                 : static inline int spl_dual_it_fetch(spl_dual_it_object *intern, int check_more TSRMLS_DC);
    1350                 : 
    1351             138 : static inline int spl_cit_check_flags(int flags)
    1352                 : {
    1353             138 :         int cnt = 0;
    1354                 : 
    1355             138 :         cnt += (flags & CIT_CALL_TOSTRING) ? 1 : 0;
    1356             138 :         cnt += (flags & CIT_TOSTRING_USE_KEY) ? 1 : 0;
    1357             138 :         cnt += (flags & CIT_TOSTRING_USE_CURRENT) ? 1 : 0;
    1358             138 :         cnt += (flags & CIT_TOSTRING_USE_INNER) ? 1 : 0;
    1359                 :         
    1360             138 :         return cnt <= 1 ? SUCCESS : FAILURE;
    1361                 : }
    1362                 : 
    1363             256 : static spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce_base, zend_class_entry *ce_inner, dual_it_type dit_type)
    1364                 : {
    1365                 :         zval                 *zobject, *retval;
    1366                 :         spl_dual_it_object   *intern;
    1367             256 :         zend_class_entry     *ce = NULL;
    1368             256 :         int                   inc_refcount = 1;
    1369                 :         zend_error_handling   error_handling;
    1370                 : 
    1371             256 :         intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
    1372                 :         
    1373             256 :         if (intern->dit_type != DIT_Unknown) {
    1374               1 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s::getIterator() must be called exactly once per instance", ce_base->name);
    1375               1 :                 return NULL;
    1376                 :         }
    1377                 : 
    1378             255 :         zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling TSRMLS_CC);
    1379                 : 
    1380             255 :         intern->dit_type = dit_type;
    1381             255 :         switch (dit_type) {
    1382                 :                 case DIT_LimitIterator: {
    1383              27 :                         intern->u.limit.offset = 0; /* start at beginning */
    1384              27 :                         intern->u.limit.count = -1; /* get all */
    1385              27 :                         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|ll", &zobject, ce_inner, &intern->u.limit.offset, &intern->u.limit.count) == FAILURE) {
    1386               1 :                                 zend_restore_error_handling(&error_handling TSRMLS_CC);
    1387               1 :                                 return NULL;
    1388                 :                         }
    1389              26 :                         if (intern->u.limit.offset < 0) {
    1390               2 :                                 zend_throw_exception(spl_ce_OutOfRangeException, "Parameter offset must be >= 0", 0 TSRMLS_CC);
    1391               2 :                                 zend_restore_error_handling(&error_handling TSRMLS_CC);
    1392               2 :                                 return NULL;
    1393                 :                         }
    1394              24 :                         if (intern->u.limit.count < 0 && intern->u.limit.count != -1) {
    1395               1 :                                 zend_throw_exception(spl_ce_OutOfRangeException, "Parameter count must either be -1 or a value greater than or equal 0", 0 TSRMLS_CC);
    1396               1 :                                 zend_restore_error_handling(&error_handling TSRMLS_CC);
    1397               1 :                                 return NULL;
    1398                 :                         }
    1399              23 :                         break;
    1400                 :                 }
    1401                 :                 case DIT_CachingIterator:
    1402                 :                 case DIT_RecursiveCachingIterator: {
    1403             132 :                         long flags = CIT_CALL_TOSTRING;
    1404             132 :                         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|l", &zobject, ce_inner, &flags) == FAILURE) {
    1405               5 :                                 zend_restore_error_handling(&error_handling TSRMLS_CC);
    1406               5 :                                 return NULL;
    1407                 :                         }
    1408             127 :                         if (spl_cit_check_flags(flags) != SUCCESS) {
    1409               1 :                                 zend_throw_exception(spl_ce_InvalidArgumentException, "Flags must contain only one of CALL_TOSTRING, TOSTRING_USE_KEY, TOSTRING_USE_CURRENT, TOSTRING_USE_CURRENT", 0 TSRMLS_CC);
    1410               1 :                                 zend_restore_error_handling(&error_handling TSRMLS_CC);
    1411               1 :                                 return NULL;
    1412                 :                         }
    1413             126 :                         intern->u.caching.flags |= flags & CIT_PUBLIC;
    1414             126 :                         MAKE_STD_ZVAL(intern->u.caching.zcache);
    1415             126 :                         array_init(intern->u.caching.zcache);
    1416             126 :                         break;
    1417                 :                 }
    1418                 :                 case DIT_IteratorIterator: {
    1419                 :                         zend_class_entry **pce_cast;
    1420              25 :                         char * class_name = NULL;
    1421              25 :                         int class_name_len = 0;
    1422                 : 
    1423              25 :                         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|s", &zobject, ce_inner, &class_name, &class_name_len) == FAILURE) {
    1424               1 :                                 zend_restore_error_handling(&error_handling TSRMLS_CC);
    1425               1 :                                 return NULL;
    1426                 :                         }
    1427              24 :                         ce = Z_OBJCE_P(zobject);
    1428              24 :                         if (!instanceof_function(ce, zend_ce_iterator TSRMLS_CC)) {
    1429              17 :                                 if (ZEND_NUM_ARGS() > 1) {
    1430              21 :                                         if (zend_lookup_class(class_name, class_name_len, &pce_cast TSRMLS_CC) == FAILURE 
    1431              14 :                                         || !instanceof_function(ce, *pce_cast TSRMLS_CC)
    1432               7 :                                         || !(*pce_cast)->get_iterator
    1433                 :                                         ) {
    1434               0 :                                                 zend_throw_exception(spl_ce_LogicException, "Class to downcast to not found or not base class or does not implement Traversable", 0 TSRMLS_CC);
    1435               0 :                                                 zend_restore_error_handling(&error_handling TSRMLS_CC);
    1436               0 :                                                 return NULL;
    1437                 :                                         }
    1438               7 :                                         ce = *pce_cast;
    1439                 :                                 }
    1440              17 :                                 if (instanceof_function(ce, zend_ce_aggregate TSRMLS_CC)) {
    1441               2 :                                         zend_call_method_with_0_params(&zobject, ce, &ce->iterator_funcs.zf_new_iterator, "getiterator", &retval);
    1442               2 :                                         if (EG(exception)) {
    1443               0 :                                                 if (retval) {
    1444               0 :                                                         zval_ptr_dtor(&retval);
    1445                 :                                                 }
    1446               0 :                                                 zend_restore_error_handling(&error_handling TSRMLS_CC);
    1447               0 :                                                 return NULL;
    1448                 :                                         }
    1449               2 :                                         if (!retval || Z_TYPE_P(retval) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(retval), zend_ce_traversable TSRMLS_CC)) {
    1450               0 :                                                 zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "%s::getIterator() must return an object that implements Traversable", ce->name);
    1451               0 :                                                 zend_restore_error_handling(&error_handling TSRMLS_CC);
    1452               0 :                                                 return NULL;
    1453                 :                                         }
    1454               2 :                                         zobject = retval;
    1455               2 :                                         ce = Z_OBJCE_P(zobject);
    1456               2 :                                         inc_refcount = 0;
    1457                 :                                 }
    1458                 :                         }
    1459              24 :                         break;
    1460                 :                 }
    1461                 :                 case DIT_AppendIterator:
    1462               8 :                         spl_instantiate(spl_ce_ArrayIterator, &intern->u.append.zarrayit, 1 TSRMLS_CC);
    1463               8 :                         zend_call_method_with_0_params(&intern->u.append.zarrayit, spl_ce_ArrayIterator, &spl_ce_ArrayIterator->constructor, "__construct", NULL);
    1464               8 :                         intern->u.append.iterator = spl_ce_ArrayIterator->get_iterator(spl_ce_ArrayIterator, intern->u.append.zarrayit, 0 TSRMLS_CC);
    1465               8 :                         zend_restore_error_handling(&error_handling TSRMLS_CC);
    1466               8 :                         return intern;
    1467                 : #if HAVE_PCRE || HAVE_BUNDLED_PCRE
    1468                 :                 case DIT_RegexIterator:
    1469                 :                 case DIT_RecursiveRegexIterator: {
    1470                 :                         char *regex;
    1471                 :                         int regex_len;
    1472              35 :                         long mode = REGIT_MODE_MATCH;
    1473                 : 
    1474              35 :                         intern->u.regex.use_flags = ZEND_NUM_ARGS() >= 5;
    1475              35 :                         intern->u.regex.flags = 0;
    1476              35 :                         intern->u.regex.preg_flags = 0;
    1477              35 :                         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|lll", &zobject, ce_inner, &regex, &regex_len, &mode, &intern->u.regex.flags, &intern->u.regex.preg_flags) == FAILURE) {
    1478               0 :                                 zend_restore_error_handling(&error_handling TSRMLS_CC);
    1479               0 :                                 return NULL;
    1480                 :                         }
    1481              35 :                         if (mode < 0 || mode >= REGIT_MODE_MAX) {
    1482               0 :                                 zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Illegal mode %ld", mode);
    1483               0 :                                 zend_restore_error_handling(&error_handling TSRMLS_CC);
    1484               0 :                                 return NULL;
    1485                 :                         }
    1486              35 :                         intern->u.regex.mode = mode;
    1487              35 :                         intern->u.regex.regex = estrndup(regex, regex_len);
    1488              35 :                         intern->u.regex.pce = pcre_get_compiled_regex_cache(regex, regex_len TSRMLS_CC);
    1489              35 :                         if (intern->u.regex.pce == NULL) {
    1490                 :                                 /* pcre_get_compiled_regex_cache has already sent error */
    1491               0 :                                 zend_restore_error_handling(&error_handling TSRMLS_CC);
    1492               0 :                                 return NULL;
    1493                 :                         }
    1494              35 :                         intern->u.regex.pce->refcount++;
    1495              35 :                         break;
    1496                 :                 }
    1497                 : #endif
    1498                 :                 default:
    1499              28 :                         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zobject, ce_inner) == FAILURE) {
    1500               3 :                                 zend_restore_error_handling(&error_handling TSRMLS_CC);
    1501               3 :                                 return NULL;
    1502                 :                         }
    1503                 :                         break;
    1504                 :         }
    1505                 : 
    1506             233 :         zend_restore_error_handling(&error_handling TSRMLS_CC);
    1507                 : 
    1508             233 :         if (inc_refcount) {
    1509             231 :                 Z_ADDREF_P(zobject);
    1510                 :         }
    1511             233 :         intern->inner.zobject = zobject;
    1512             233 :         intern->inner.ce = dit_type == DIT_IteratorIterator ? ce : Z_OBJCE_P(zobject);
    1513             233 :         intern->inner.object = zend_object_store_get_object(zobject TSRMLS_CC);
    1514             233 :         intern->inner.iterator = intern->inner.ce->get_iterator(intern->inner.ce, zobject, 0 TSRMLS_CC);
    1515                 : 
    1516             233 :         return intern;
    1517                 : }
    1518                 : 
    1519                 : /* {{{ proto void FilterIterator::__construct(Iterator it) 
    1520                 :    Create an Iterator from another iterator */
    1521               3 : SPL_METHOD(FilterIterator, __construct)
    1522                 : {
    1523               3 :         spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_FilterIterator, zend_ce_iterator, DIT_FilterIterator);
    1524               3 : } /* }}} */
    1525                 : 
    1526                 : /* {{{ proto Iterator FilterIterator::getInnerIterator() 
    1527                 :        proto Iterator CachingIterator::getInnerIterator()
    1528                 :        proto Iterator LimitIterator::getInnerIterator()
    1529                 :        proto Iterator ParentIterator::getInnerIterator()
    1530                 :    Get the inner iterator */
    1531               5 : SPL_METHOD(dual_it, getInnerIterator)
    1532                 : {
    1533                 :         spl_dual_it_object   *intern;
    1534                 :         
    1535               5 :         if (zend_parse_parameters_none() == FAILURE) {
    1536               0 :                 return;
    1537                 :         }
    1538                 :         
    1539               5 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    1540                 : 
    1541               5 :         if (intern->inner.zobject) {
    1542              10 :                 RETVAL_ZVAL(intern->inner.zobject, 1, 0);
    1543                 :         } else {
    1544               0 :                 RETURN_NULL();
    1545                 :         }
    1546                 : } /* }}} */
    1547                 : 
    1548             285 : static inline void spl_dual_it_require(spl_dual_it_object *intern TSRMLS_DC)
    1549                 : {
    1550             285 :         if (!intern->inner.iterator) {
    1551               0 :                 php_error_docref(NULL TSRMLS_CC, E_ERROR, "The inner constructor wasn't initialized with an iterator instance");
    1552                 :         }
    1553             285 : }
    1554                 : 
    1555            4349 : static inline void spl_dual_it_free(spl_dual_it_object *intern TSRMLS_DC)
    1556                 : {
    1557            4349 :         if (intern->inner.iterator && intern->inner.iterator->funcs->invalidate_current) {
    1558             219 :                 intern->inner.iterator->funcs->invalidate_current(intern->inner.iterator TSRMLS_CC);
    1559                 :         }
    1560            4349 :         if (intern->current.data) {
    1561            3137 :                 zval_ptr_dtor(&intern->current.data);
    1562            3137 :                 intern->current.data = NULL;
    1563                 :         }
    1564            4349 :         if (intern->current.str_key) {
    1565            1433 :                 efree(intern->current.str_key);
    1566            1433 :                 intern->current.str_key = NULL;
    1567                 :         }
    1568            4349 :         if (intern->dit_type == DIT_CachingIterator || intern->dit_type == DIT_RecursiveCachingIterator) {
    1569             636 :                 if (intern->u.caching.zstr) {
    1570              36 :                         zval_ptr_dtor(&intern->u.caching.zstr);
    1571              36 :                         intern->u.caching.zstr = NULL;
    1572                 :                 }
    1573             636 :                 if (intern->u.caching.zchildren) {
    1574              72 :                         zval_ptr_dtor(&intern->u.caching.zchildren);
    1575              72 :                         intern->u.caching.zchildren = NULL;
    1576                 :                 }
    1577                 :         }
    1578            4349 : }
    1579                 : 
    1580             242 : static inline void spl_dual_it_rewind(spl_dual_it_object *intern TSRMLS_DC)
    1581                 : {
    1582             242 :         spl_dual_it_free(intern TSRMLS_CC);
    1583             242 :         intern->current.pos = 0;
    1584             242 :         if (intern->inner.iterator->funcs->rewind) {
    1585             228 :                 intern->inner.iterator->funcs->rewind(intern->inner.iterator TSRMLS_CC);
    1586                 :         }
    1587             242 : }
    1588                 : 
    1589            4037 : static inline int spl_dual_it_valid(spl_dual_it_object *intern TSRMLS_DC)
    1590                 : {
    1591            4037 :         if (!intern->inner.iterator) {
    1592               2 :                 return FAILURE;
    1593                 :         }
    1594                 :         /* FAILURE / SUCCESS */
    1595            4035 :         return intern->inner.iterator->funcs->valid(intern->inner.iterator TSRMLS_CC);
    1596                 : }
    1597                 : 
    1598            3313 : static inline int spl_dual_it_fetch(spl_dual_it_object *intern, int check_more TSRMLS_DC)
    1599                 : {
    1600                 :         zval **data;
    1601                 : 
    1602            3313 :         spl_dual_it_free(intern TSRMLS_CC);
    1603            3313 :         if (!check_more || spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
    1604            3139 :                 intern->inner.iterator->funcs->get_current_data(intern->inner.iterator, &data TSRMLS_CC);
    1605            3139 :                 if (data && *data) {
    1606            3138 :                         intern->current.data = *data;
    1607            3138 :                         Z_ADDREF_P(intern->current.data);
    1608                 :                 }
    1609            3139 :                 if (intern->inner.iterator->funcs->get_current_key) {
    1610            3139 :                         intern->current.key_type = intern->inner.iterator->funcs->get_current_key(intern->inner.iterator, &intern->current.str_key, &intern->current.str_key_len, &intern->current.int_key TSRMLS_CC);
    1611                 :                 } else {
    1612               0 :                         intern->current.key_type = HASH_KEY_IS_LONG;
    1613               0 :                         intern->current.int_key = intern->current.pos;
    1614                 :                 }
    1615            3139 :                 return EG(exception) ? FAILURE : SUCCESS;
    1616                 :         }
    1617             174 :         return FAILURE;
    1618                 : }
    1619                 : 
    1620             700 : static inline void spl_dual_it_next(spl_dual_it_object *intern, int do_free TSRMLS_DC)
    1621                 : {
    1622             700 :         if (do_free) {
    1623             415 :                 spl_dual_it_free(intern TSRMLS_CC);
    1624                 :         } else {
    1625             285 :                 spl_dual_it_require(intern TSRMLS_CC);
    1626                 :         }
    1627             700 :         intern->inner.iterator->funcs->move_forward(intern->inner.iterator TSRMLS_CC);
    1628             700 :         intern->current.pos++;
    1629             700 : }
    1630                 : 
    1631                 : /* {{{ proto void ParentIterator::rewind()
    1632                 :        proto void IteratorIterator::rewind()
    1633                 :    Rewind the iterator
    1634                 :    */
    1635              29 : SPL_METHOD(dual_it, rewind)
    1636                 : {
    1637                 :         spl_dual_it_object   *intern;
    1638                 :         
    1639              29 :         if (zend_parse_parameters_none() == FAILURE) {
    1640               0 :                 return;
    1641                 :         }
    1642                 :         
    1643              29 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    1644                 :         
    1645              27 :         spl_dual_it_rewind(intern TSRMLS_CC);
    1646              27 :         spl_dual_it_fetch(intern, 1 TSRMLS_CC);
    1647                 : } /* }}} */
    1648                 : 
    1649                 : /* {{{ proto bool FilterIterator::valid()
    1650                 :        proto bool ParentIterator::valid()
    1651                 :        proto bool IteratorIterator::valid()
    1652                 :        proto bool NoRewindIterator::valid()
    1653                 :    Check whether the current element is valid */
    1654             371 : SPL_METHOD(dual_it, valid)
    1655                 : {
    1656                 :         spl_dual_it_object   *intern;
    1657                 : 
    1658             371 :         if (zend_parse_parameters_none() == FAILURE) {
    1659               0 :                 return;
    1660                 :         }
    1661                 :         
    1662             371 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    1663                 : 
    1664             371 :         RETURN_BOOL(intern->current.data);
    1665                 : } /* }}} */
    1666                 : 
    1667                 : /* {{{ proto mixed FilterIterator::key()
    1668                 :        proto mixed CachingIterator::key()
    1669                 :        proto mixed LimitIterator::key()
    1670                 :        proto mixed ParentIterator::key()
    1671                 :        proto mixed IteratorIterator::key()
    1672                 :        proto mixed NoRewindIterator::key()
    1673                 :        proto mixed AppendIterator::key()
    1674                 :    Get the current key */
    1675             467 : SPL_METHOD(dual_it, key)
    1676                 : {
    1677                 :         spl_dual_it_object   *intern;
    1678                 : 
    1679             467 :         if (zend_parse_parameters_none() == FAILURE) {
    1680               0 :                 return;
    1681                 :         }
    1682                 :         
    1683             467 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    1684                 : 
    1685             467 :         if (intern->current.data) {
    1686             466 :                 if (intern->current.key_type == HASH_KEY_IS_STRING) {
    1687              93 :                         RETURN_STRINGL(intern->current.str_key, intern->current.str_key_len-1, 1);
    1688                 :                 } else {
    1689             373 :                         RETURN_LONG(intern->current.int_key);
    1690                 :                 }
    1691                 :         }
    1692               1 :         RETURN_NULL();
    1693                 : } /* }}} */
    1694                 : 
    1695                 : /* {{{ proto mixed FilterIterator::current()
    1696                 :        proto mixed CachingIterator::current()
    1697                 :        proto mixed LimitIterator::current()
    1698                 :        proto mixed ParentIterator::current()
    1699                 :        proto mixed IteratorIterator::current()
    1700                 :        proto mixed NoRewindIterator::current()
    1701                 :        proto mixed AppendIterator::current()
    1702                 :    Get the current element value */
    1703             726 : SPL_METHOD(dual_it, current)
    1704                 : {
    1705                 :         spl_dual_it_object   *intern;
    1706                 :         
    1707             726 :         if (zend_parse_parameters_none() == FAILURE) {
    1708               0 :                 return;
    1709                 :         }
    1710                 : 
    1711             726 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    1712                 : 
    1713             726 :         if (intern->current.data) {
    1714            1436 :                 RETVAL_ZVAL(intern->current.data, 1, 0);
    1715                 :         } else {
    1716               8 :                 RETURN_NULL();
    1717                 :         }
    1718                 : } /* }}} */
    1719                 : 
    1720                 : /* {{{ proto void ParentIterator::next()
    1721                 :        proto void IteratorIterator::next()
    1722                 :        proto void NoRewindIterator::next()
    1723                 :    Move the iterator forward */
    1724              53 : SPL_METHOD(dual_it, next)
    1725                 : {
    1726                 :         spl_dual_it_object   *intern;
    1727                 :         
    1728              53 :         if (zend_parse_parameters_none() == FAILURE) {
    1729               0 :                 return;
    1730                 :         }
    1731                 : 
    1732              53 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    1733                 : 
    1734              53 :         spl_dual_it_next(intern, 1 TSRMLS_CC);
    1735              53 :         spl_dual_it_fetch(intern, 1 TSRMLS_CC);
    1736                 : } /* }}} */
    1737                 : 
    1738             244 : static inline void spl_filter_it_fetch(zval *zthis, spl_dual_it_object *intern TSRMLS_DC)
    1739                 : {
    1740                 :         zval *retval;
    1741                 : 
    1742            2927 :         while (spl_dual_it_fetch(intern, 1 TSRMLS_CC) == SUCCESS) {
    1743            2648 :                 zend_call_method_with_0_params(&zthis, intern->std.ce, NULL, "accept", &retval);
    1744            2648 :                 if (retval) {
    1745            2647 :                         if (zend_is_true(retval)) {
    1746             208 :                                 zval_ptr_dtor(&retval);
    1747             208 :                                 return;
    1748                 :                         }
    1749            2439 :                         zval_ptr_dtor(&retval);
    1750                 :                 }
    1751            2440 :                 if (EG(exception)) {
    1752               1 :                         return;
    1753                 :                 }
    1754            2439 :                 intern->inner.iterator->funcs->move_forward(intern->inner.iterator TSRMLS_CC);
    1755                 :         }
    1756              35 :         spl_dual_it_free(intern TSRMLS_CC);
    1757                 : }
    1758                 : 
    1759              36 : static inline void spl_filter_it_rewind(zval *zthis, spl_dual_it_object *intern TSRMLS_DC)
    1760                 : {
    1761              36 :         spl_dual_it_rewind(intern TSRMLS_CC);
    1762              36 :         spl_filter_it_fetch(zthis, intern TSRMLS_CC);
    1763              36 : }
    1764                 : 
    1765             208 : static inline void spl_filter_it_next(zval *zthis, spl_dual_it_object *intern TSRMLS_DC)
    1766                 : {
    1767             208 :         spl_dual_it_next(intern, 1 TSRMLS_CC);
    1768             208 :         spl_filter_it_fetch(zthis, intern TSRMLS_CC);
    1769             208 : }
    1770                 : 
    1771                 : /* {{{ proto void FilterIterator::rewind()
    1772                 :    Rewind the iterator */
    1773              38 : SPL_METHOD(FilterIterator, rewind)
    1774                 : {
    1775                 :         spl_dual_it_object   *intern;
    1776                 :         
    1777              38 :         if (zend_parse_parameters_none() == FAILURE) {
    1778               0 :                 return;
    1779                 :         }
    1780                 : 
    1781              38 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    1782              36 :         spl_filter_it_rewind(getThis(), intern TSRMLS_CC);
    1783                 : } /* }}} */
    1784                 : 
    1785                 : /* {{{ proto void FilterIterator::next()
    1786                 :    Move the iterator forward */
    1787             208 : SPL_METHOD(FilterIterator, next)
    1788                 : {
    1789                 :         spl_dual_it_object   *intern;
    1790                 :         
    1791             208 :         if (zend_parse_parameters_none() == FAILURE) {
    1792               0 :                 return;
    1793                 :         }
    1794                 : 
    1795             208 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    1796             208 :         spl_filter_it_next(getThis(), intern TSRMLS_CC);
    1797                 : } /* }}} */
    1798                 : 
    1799                 : /* {{{ proto void RecursiveFilterIterator::__construct(RecursiveIterator it)
    1800                 :    Create a RecursiveFilterIterator from a RecursiveIterator */
    1801               2 : SPL_METHOD(RecursiveFilterIterator, __construct)
    1802                 : {
    1803               2 :         spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveFilterIterator, spl_ce_RecursiveIterator, DIT_RecursiveFilterIterator);
    1804               2 : } /* }}} */
    1805                 : 
    1806                 : /* {{{ proto bool RecursiveFilterIterator::hasChildren()
    1807                 :    Check whether the inner iterator's current element has children */
    1808              37 : SPL_METHOD(RecursiveFilterIterator, hasChildren)
    1809                 : {
    1810                 :         spl_dual_it_object   *intern;
    1811                 :         zval                 *retval;
    1812                 :         
    1813              37 :         if (zend_parse_parameters_none() == FAILURE) {
    1814               0 :                 return;
    1815                 :         }
    1816                 : 
    1817              37 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    1818                 : 
    1819              34 :         zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "haschildren", &retval);
    1820              34 :         if (retval) {
    1821             102 :                 RETURN_ZVAL(retval, 0, 1);
    1822                 :         } else {
    1823               0 :                 RETURN_FALSE;
    1824                 :         }
    1825                 : } /* }}} */
    1826                 : 
    1827                 : /* {{{ proto RecursiveFilterIterator RecursiveFilterIterator::getChildren()
    1828                 :    Return the inner iterator's children contained in a RecursiveFilterIterator */
    1829               5 : SPL_METHOD(RecursiveFilterIterator, getChildren)
    1830                 : {
    1831                 :         spl_dual_it_object   *intern;
    1832                 :         zval                 *retval;
    1833                 :         
    1834               5 :         if (zend_parse_parameters_none() == FAILURE) {
    1835               0 :                 return;
    1836                 :         }
    1837                 : 
    1838               5 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    1839                 : 
    1840               5 :         zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &retval);
    1841               5 :         if (!EG(exception) && retval) {
    1842               5 :                 spl_instantiate_arg_ex1(Z_OBJCE_P(getThis()), &return_value, 0, retval TSRMLS_CC);
    1843                 :         }
    1844               5 :         if (retval) {
    1845               5 :                 zval_ptr_dtor(&retval);
    1846                 :         }
    1847                 : } /* }}} */
    1848                 : 
    1849                 : /* {{{ proto void ParentIterator::__construct(RecursiveIterator it)
    1850                 :    Create a ParentIterator from a RecursiveIterator */
    1851               6 : SPL_METHOD(ParentIterator, __construct)
    1852                 : {
    1853               6 :         spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_ParentIterator, spl_ce_RecursiveIterator, DIT_ParentIterator);
    1854               6 : } /* }}} */
    1855                 : 
    1856                 : #if HAVE_PCRE || HAVE_BUNDLED_PCRE
    1857                 : /* {{{ proto void RegexIterator::__construct(Iterator it, string regex [, int mode [, int flags [, int preg_flags]]]) 
    1858                 :    Create an RegexIterator from another iterator and a regular expression */
    1859              32 : SPL_METHOD(RegexIterator, __construct)
    1860                 : {
    1861              32 :         spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RegexIterator, zend_ce_iterator, DIT_RegexIterator);
    1862              32 : } /* }}} */
    1863                 : 
    1864                 : /* {{{ proto bool RegexIterator::accept()
    1865                 :    Match (string)current() against regular expression */
    1866            2624 : SPL_METHOD(RegexIterator, accept)
    1867                 : {
    1868                 :         spl_dual_it_object *intern;
    1869                 :         char       *subject, tmp[32], *result;
    1870            2624 :         int        subject_len, use_copy, count = 0, result_len;
    1871                 :         zval       subject_copy, zcount, *replacement, tmp_replacement;
    1872                 :         
    1873            2624 :         if (zend_parse_parameters_none() == FAILURE) {
    1874               0 :                 return;
    1875                 :         }
    1876                 :         
    1877            2624 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    1878                 :         
    1879            2624 :         if (intern->current.data == NULL) {
    1880               1 :                 RETURN_FALSE;
    1881                 :         }
    1882                 :         
    1883            2623 :         if (intern->u.regex.flags & REGIT_USE_KEY) {
    1884              47 :                 if (intern->current.key_type == HASH_KEY_IS_LONG) {
    1885              31 :                         subject_len = slprintf(tmp, sizeof(tmp), "%ld", intern->current.int_key);
    1886              31 :                         subject = &tmp[0];
    1887              31 :                         use_copy = 0;
    1888                 :                 } else {
    1889              16 :                         subject_len = intern->current.str_key_len - 1;
    1890              16 :                         subject = estrndup(intern->current.str_key, subject_len);
    1891              16 :                         use_copy = 1;
    1892                 :                 }
    1893                 :         } else {
    1894            2576 :                 zend_make_printable_zval(intern->current.data, &subject_copy, &use_copy);
    1895            2576 :                 if (use_copy) {
    1896            2523 :                         subject = Z_STRVAL(subject_copy);
    1897            2523 :                         subject_len = Z_STRLEN(subject_copy);
    1898                 :                 } else {
    1899              53 :                         subject = Z_STRVAL_P(intern->current.data);
    1900              53 :                         subject_len = Z_STRLEN_P(intern->current.data);
    1901                 :                 }
    1902                 :         }
    1903                 : 
    1904            2623 :         switch (intern->u.regex.mode)
    1905                 :         {
    1906                 :         case REGIT_MODE_MAX: /* won't happen but makes compiler happy */
    1907                 :         case REGIT_MODE_MATCH:
    1908            2529 :                 count = pcre_exec(intern->u.regex.pce->re, intern->u.regex.pce->extra, subject, subject_len, 0, 0, NULL, 0);
    1909            2529 :                 RETVAL_BOOL(count >= 0);
    1910            2529 :                 break;
    1911                 : 
    1912                 :         case REGIT_MODE_ALL_MATCHES:
    1913                 :         case REGIT_MODE_GET_MATCH:
    1914              68 :                 if (!use_copy) {
    1915              50 :                         subject = estrndup(subject, subject_len);
    1916              50 :                         use_copy = 1;
    1917                 :                 }
    1918              68 :                 zval_ptr_dtor(&intern->current.data);
    1919              68 :                 ALLOC_INIT_ZVAL(intern->current.data);
    1920              68 :                 php_pcre_match_impl(intern->u.regex.pce, subject, subject_len, &zcount, 
    1921                 :                         intern->current.data, intern->u.regex.mode == REGIT_MODE_ALL_MATCHES, intern->u.regex.use_flags, intern->u.regex.preg_flags, 0 TSRMLS_CC);
    1922              68 :                 count = zend_hash_num_elements(Z_ARRVAL_P(intern->current.data));
    1923              68 :                 RETVAL_BOOL(count > 0);
    1924              68 :                 break;
    1925                 : 
    1926                 :         case REGIT_MODE_SPLIT:
    1927              16 :                 if (!use_copy) {
    1928               9 :                         subject = estrndup(subject, subject_len);
    1929               9 :                         use_copy = 1;
    1930                 :                 }
    1931              16 :                 zval_ptr_dtor(&intern->current.data);
    1932              16 :                 ALLOC_INIT_ZVAL(intern->current.data);
    1933              16 :                 php_pcre_split_impl(intern->u.regex.pce, subject, subject_len, intern->current.data, -1, intern->u.regex.preg_flags TSRMLS_CC);
    1934              16 :                 count = zend_hash_num_elements(Z_ARRVAL_P(intern->current.data));
    1935              16 :                 RETVAL_BOOL(count > 1);
    1936              16 :                 break;
    1937                 : 
    1938                 :         case REGIT_MODE_REPLACE:
    1939              10 :                 replacement = zend_read_property(intern->std.ce, getThis(), "replacement", sizeof("replacement")-1, 1 TSRMLS_CC);
    1940              10 :                 if (Z_TYPE_P(replacement) != IS_STRING) {
    1941               1 :                         tmp_replacement = *replacement;
    1942               1 :                         zval_copy_ctor(&tmp_replacement);
    1943               1 :                         convert_to_string(&tmp_replacement);
    1944               1 :                         replacement = &tmp_replacement;
    1945                 :                 }
    1946              10 :                 result = php_pcre_replace_impl(intern->u.regex.pce, subject, subject_len, replacement, 0, &result_len, -1, &count TSRMLS_CC);
    1947                 :                 
    1948              10 :                 if (intern->u.regex.flags & REGIT_USE_KEY) {
    1949               0 :                         if (intern->current.key_type != HASH_KEY_IS_LONG) {
    1950               0 :                                 efree(intern->current.str_key);
    1951                 :                         }
    1952               0 :                         intern->current.key_type = HASH_KEY_IS_STRING;
    1953               0 :                         intern->current.str_key = result;
    1954               0 :                         intern->current.str_key_len = result_len + 1;
    1955                 :                 } else {
    1956              10 :                         zval_ptr_dtor(&intern->current.data);
    1957              10 :                         MAKE_STD_ZVAL(intern->current.data);
    1958              10 :                         ZVAL_STRINGL(intern->current.data, result, result_len, 0);
    1959                 :                 }
    1960                 : 
    1961              10 :                 if (replacement == &tmp_replacement) {
    1962               1 :                         zval_dtor(replacement);
    1963                 :                 }
    1964              10 :                 RETVAL_BOOL(count > 0);
    1965                 :         }
    1966                 : 
    1967            2623 :         if (intern->u.regex.flags & REGIT_INVERTED) {
    1968               0 :                 RETVAL_BOOL(Z_LVAL_P(return_value));
    1969                 :         }
    1970                 : 
    1971            2623 :         if (use_copy) {
    1972            2598 :                 efree(subject);
    1973                 :         }
    1974                 : } /* }}} */
    1975                 : 
    1976                 : /* {{{ proto bool RegexIterator::getMode()
    1977                 :    Returns current operation mode */
    1978               6 : SPL_METHOD(RegexIterator, getMode)
    1979                 : {
    1980                 :         spl_dual_it_object *intern;
    1981                 : 
    1982               6 :         if (zend_parse_parameters_none() == FAILURE) {
    1983               0 :                 return;
    1984                 :         }
    1985                 :         
    1986               6 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    1987                 :         
    1988               6 :         RETURN_LONG(intern->u.regex.mode);
    1989                 : } /* }}} */
    1990                 : 
    1991                 : /* {{{ proto bool RegexIterator::setMode(int new_mode)
    1992                 :    Set new operation mode */
    1993               6 : SPL_METHOD(RegexIterator, setMode)
    1994                 : {
    1995                 :         spl_dual_it_object *intern;
    1996                 :         long mode;
    1997                 : 
    1998               6 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &mode) == FAILURE) {
    1999               1 :                 return;
    2000                 :         }
    2001                 : 
    2002               5 :         if (mode < 0 || mode >= REGIT_MODE_MAX) {
    2003               1 :                 zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Illegal mode %ld", mode);
    2004               1 :                 return;/* NULL */
    2005                 :         }
    2006                 :         
    2007               4 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    2008                 : 
    2009               4 :         intern->u.regex.mode = mode;
    2010                 : } /* }}} */
    2011                 : 
    2012                 : /* {{{ proto bool RegexIterator::getFlags()
    2013                 :    Returns current operation flags */
    2014               3 : SPL_METHOD(RegexIterator, getFlags)
    2015                 : {
    2016                 :         spl_dual_it_object *intern;
    2017                 : 
    2018               3 :         if (zend_parse_parameters_none() == FAILURE) {
    2019               0 :                 return;
    2020                 :         }
    2021                 :         
    2022               3 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    2023                 :         
    2024               3 :         RETURN_LONG(intern->u.regex.flags);
    2025                 : } /* }}} */
    2026                 : 
    2027                 : /* {{{ proto bool RegexIterator::setFlags(int new_flags)
    2028                 :    Set operation flags */
    2029               3 : SPL_METHOD(RegexIterator, setFlags)
    2030                 : {
    2031                 :         spl_dual_it_object *intern;
    2032                 :         long flags;
    2033                 : 
    2034               3 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &flags) == FAILURE) {
    2035               1 :                 return;
    2036                 :         }
    2037                 :         
    2038               2 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    2039                 : 
    2040               2 :         intern->u.regex.flags = flags;
    2041                 : } /* }}} */
    2042                 : 
    2043                 : /* {{{ proto bool RegexIterator::getFlags()
    2044                 :    Returns current PREG flags (if in use or NULL) */
    2045               2 : SPL_METHOD(RegexIterator, getPregFlags)
    2046                 : {
    2047                 :         spl_dual_it_object *intern;
    2048                 :         
    2049               2 :         if (zend_parse_parameters_none() == FAILURE) {
    2050               0 :                 return;
    2051                 :         }
    2052                 :         
    2053               2 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    2054                 : 
    2055               2 :         if (intern->u.regex.use_flags) {
    2056               2 :                 RETURN_LONG(intern->u.regex.preg_flags);
    2057                 :         } else {
    2058               0 :                 return;
    2059                 :         }
    2060                 : } /* }}} */
    2061                 : 
    2062                 : /* {{{ proto bool RegexIterator::setPregFlags(int new_flags)
    2063                 :    Set PREG flags */
    2064               3 : SPL_METHOD(RegexIterator, setPregFlags)
    2065                 : {
    2066                 :         spl_dual_it_object *intern;
    2067                 :         long preg_flags;
    2068                 : 
    2069               3 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &preg_flags) == FAILURE) {
    2070               1 :                 return;
    2071                 :         }
    2072                 :         
    2073               2 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    2074                 : 
    2075               2 :         intern->u.regex.preg_flags = preg_flags;
    2076               2 :         intern->u.regex.use_flags = 1;
    2077                 : } /* }}} */
    2078                 : 
    2079                 : /* {{{ proto void RecursiveRegexIterator::__construct(RecursiveIterator it, string regex [, int mode [, int flags [, int preg_flags]]]) 
    2080                 :    Create an RecursiveRegexIterator from another recursive iterator and a regular expression */
    2081               3 : SPL_METHOD(RecursiveRegexIterator, __construct)
    2082                 : {
    2083               3 :         spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveRegexIterator, spl_ce_RecursiveIterator, DIT_RecursiveRegexIterator);
    2084               3 : } /* }}} */
    2085                 : 
    2086                 : /* {{{ proto RecursiveRegexIterator RecursiveRegexIterator::getChildren()
    2087                 :    Return the inner iterator's children contained in a RecursiveRegexIterator */
    2088               2 : SPL_METHOD(RecursiveRegexIterator, getChildren)
    2089                 : {
    2090                 :         spl_dual_it_object   *intern;
    2091                 :         zval                 *retval, *regex;
    2092                 :         
    2093               2 :         if (zend_parse_parameters_none() == FAILURE) {
    2094               0 :                 return;
    2095                 :         }
    2096                 : 
    2097               2 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    2098                 : 
    2099               2 :         zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &retval);
    2100               2 :         if (!EG(exception)) {
    2101               2 :                 MAKE_STD_ZVAL(regex);
    2102               2 :                 ZVAL_STRING(regex, intern->u.regex.regex, 1);
    2103               2 :                 spl_instantiate_arg_ex2(Z_OBJCE_P(getThis()), &return_value, 0, retval, regex TSRMLS_CC);
    2104               2 :                 zval_ptr_dtor(&regex);
    2105                 :         }
    2106               2 :         if (retval) {
    2107               2 :                 zval_ptr_dtor(&retval);
    2108                 :         }
    2109                 : } /* }}} */
    2110                 : 
    2111                 : #endif
    2112                 : 
    2113                 : /* {{{ spl_dual_it_dtor */
    2114             251 : static void spl_dual_it_dtor(zend_object *_object, zend_object_handle handle TSRMLS_DC)
    2115                 : {
    2116             251 :         spl_dual_it_object        *object = (spl_dual_it_object *)_object;
    2117                 : 
    2118                 :         /* call standard dtor */
    2119             251 :         zend_objects_destroy_object(_object, handle TSRMLS_CC);
    2120                 : 
    2121             251 :         spl_dual_it_free(object TSRMLS_CC);
    2122                 : 
    2123             251 :         if (object->inner.iterator) {
    2124             231 :                 object->inner.iterator->funcs->dtor(object->inner.iterator TSRMLS_CC);
    2125                 :         }
    2126             251 : }
    2127                 : /* }}} */
    2128                 : 
    2129                 : /* {{{ spl_dual_it_free_storage */
    2130             267 : static void spl_dual_it_free_storage(void *_object TSRMLS_DC)
    2131                 : {
    2132             267 :         spl_dual_it_object        *object = (spl_dual_it_object *)_object;
    2133                 : 
    2134             267 :         if (object->inner.zobject) {
    2135             233 :                 zval_ptr_dtor(&object->inner.zobject);
    2136                 :         }
    2137                 :         
    2138             267 :         if (object->dit_type == DIT_AppendIterator) {
    2139               8 :                 object->u.append.iterator->funcs->dtor(object->u.append.iterator TSRMLS_CC);
    2140               8 :                 if (object->u.append.zarrayit) {
    2141               8 :                         zval_ptr_dtor(&object->u.append.zarrayit);
    2142                 :                 }
    2143                 :         }
    2144                 : 
    2145             267 :         if (object->dit_type == DIT_CachingIterator || object->dit_type == DIT_RecursiveCachingIterator) {
    2146             132 :                 if (object->u.caching.zcache) {
    2147             126 :                         zval_ptr_dtor(&object->u.caching.zcache);
    2148             126 :                         object->u.caching.zcache = NULL;
    2149                 :                 }
    2150                 :         }
    2151                 : 
    2152                 : #if HAVE_PCRE || HAVE_BUNDLED_PCRE
    2153             267 :         if (object->dit_type == DIT_RegexIterator || object->dit_type == DIT_RecursiveRegexIterator) {
    2154              35 :                 if (object->u.regex.pce) {
    2155              35 :                         object->u.regex.pce->refcount--;
    2156                 :                 }
    2157              35 :                 if (object->u.regex.regex) {
    2158              35 :                         efree(object->u.regex.regex);
    2159                 :                 }
    2160                 :         }
    2161                 : #endif
    2162                 : 
    2163             267 :         zend_object_std_dtor(&object->std TSRMLS_CC);
    2164                 : 
    2165             267 :         efree(object);
    2166             267 : }
    2167                 : /* }}} */
    2168                 : 
    2169                 : /* {{{ spl_dual_it_new */
    2170             267 : static zend_object_value spl_dual_it_new(zend_class_entry *class_type TSRMLS_DC)
    2171                 : {
    2172                 :         zend_object_value retval;
    2173                 :         spl_dual_it_object *intern;
    2174                 :         zval *tmp;
    2175                 : 
    2176             267 :         intern = emalloc(sizeof(spl_dual_it_object));
    2177             267 :         memset(intern, 0, sizeof(spl_dual_it_object));
    2178             267 :         intern->dit_type = DIT_Unknown;
    2179                 : 
    2180             267 :         zend_object_std_init(&intern->std, class_type TSRMLS_CC);
    2181             267 :         zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
    2182                 : 
    2183             267 :         retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)spl_dual_it_dtor, (zend_objects_free_object_storage_t) spl_dual_it_free_storage, NULL TSRMLS_CC);
    2184             267 :         retval.handlers = &spl_handlers_dual_it;
    2185             267 :         return retval;
    2186                 : }
    2187                 : /* }}} */
    2188                 : 
    2189                 : ZEND_BEGIN_ARG_INFO(arginfo_filter_it___construct, 0) 
    2190                 :         ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
    2191                 : ZEND_END_ARG_INFO();
    2192                 : 
    2193                 : static const zend_function_entry spl_funcs_FilterIterator[] = {
    2194                 :         SPL_ME(FilterIterator,  __construct,      arginfo_filter_it___construct, ZEND_ACC_PUBLIC)
    2195                 :         SPL_ME(FilterIterator,  rewind,           arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    2196                 :         SPL_ME(dual_it,         valid,            arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    2197                 :         SPL_ME(dual_it,         key,              arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    2198                 :         SPL_ME(dual_it,         current,          arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    2199                 :         SPL_ME(FilterIterator,  next,             arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    2200                 :         SPL_ME(dual_it,         getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    2201                 :         SPL_ABSTRACT_ME(FilterIterator, accept,   arginfo_recursive_it_void)
    2202                 :         PHP_FE_END
    2203                 : };
    2204                 : 
    2205                 : ZEND_BEGIN_ARG_INFO(arginfo_parent_it___construct, 0) 
    2206                 :         ZEND_ARG_OBJ_INFO(0, iterator, RecursiveIterator, 0)
    2207                 : ZEND_END_ARG_INFO();
    2208                 : 
    2209                 : static const zend_function_entry spl_funcs_RecursiveFilterIterator[] = {
    2210                 :         SPL_ME(RecursiveFilterIterator,  __construct,      arginfo_parent_it___construct, ZEND_ACC_PUBLIC)
    2211                 :         SPL_ME(RecursiveFilterIterator,  hasChildren,      arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    2212                 :         SPL_ME(RecursiveFilterIterator,  getChildren,      arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    2213                 :         PHP_FE_END
    2214                 : };
    2215                 : 
    2216                 : static const zend_function_entry spl_funcs_ParentIterator[] = {
    2217                 :         SPL_ME(ParentIterator,  __construct,      arginfo_parent_it___construct, ZEND_ACC_PUBLIC)
    2218                 :         SPL_MA(ParentIterator,  accept,           RecursiveFilterIterator, hasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    2219                 :         PHP_FE_END
    2220                 : };
    2221                 : 
    2222                 : #if HAVE_PCRE || HAVE_BUNDLED_PCRE
    2223                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it___construct, 0, 0, 2) 
    2224                 :         ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
    2225                 :         ZEND_ARG_INFO(0, regex)
    2226                 :         ZEND_ARG_INFO(0, mode)
    2227                 :         ZEND_ARG_INFO(0, flags)
    2228                 :         ZEND_ARG_INFO(0, preg_flags)
    2229                 : ZEND_END_ARG_INFO();
    2230                 : 
    2231                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it_set_mode, 0, 0, 1) 
    2232                 :         ZEND_ARG_INFO(0, mode)
    2233                 : ZEND_END_ARG_INFO();
    2234                 : 
    2235                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it_set_flags, 0, 0, 1) 
    2236                 :         ZEND_ARG_INFO(0, flags)
    2237                 : ZEND_END_ARG_INFO();
    2238                 : 
    2239                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it_set_preg_flags, 0, 0, 1) 
    2240                 :         ZEND_ARG_INFO(0, preg_flags)
    2241                 : ZEND_END_ARG_INFO();
    2242                 : 
    2243                 : static const zend_function_entry spl_funcs_RegexIterator[] = {
    2244                 :         SPL_ME(RegexIterator,   __construct,      arginfo_regex_it___construct,    ZEND_ACC_PUBLIC)
    2245                 :         SPL_ME(RegexIterator,   accept,           arginfo_recursive_it_void,       ZEND_ACC_PUBLIC)
    2246                 :         SPL_ME(RegexIterator,   getMode,          arginfo_recursive_it_void,       ZEND_ACC_PUBLIC)
    2247                 :         SPL_ME(RegexIterator,   setMode,          arginfo_regex_it_set_mode,       ZEND_ACC_PUBLIC)
    2248                 :         SPL_ME(RegexIterator,   getFlags,         arginfo_recursive_it_void,       ZEND_ACC_PUBLIC)
    2249                 :         SPL_ME(RegexIterator,   setFlags,         arginfo_regex_it_set_flags,      ZEND_ACC_PUBLIC)
    2250                 :         SPL_ME(RegexIterator,   getPregFlags,     arginfo_recursive_it_void,       ZEND_ACC_PUBLIC)
    2251                 :         SPL_ME(RegexIterator,   setPregFlags,     arginfo_regex_it_set_preg_flags, ZEND_ACC_PUBLIC)
    2252                 :         PHP_FE_END
    2253                 : };
    2254                 : 
    2255                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_rec_regex_it___construct, 0, 0, 2) 
    2256                 :         ZEND_ARG_OBJ_INFO(0, iterator, RecursiveIterator, 0)
    2257                 :         ZEND_ARG_INFO(0, regex)
    2258                 :         ZEND_ARG_INFO(0, mode)
    2259                 :         ZEND_ARG_INFO(0, flags)
    2260                 :         ZEND_ARG_INFO(0, preg_flags)
    2261                 : ZEND_END_ARG_INFO();
    2262                 : 
    2263                 : static const zend_function_entry spl_funcs_RecursiveRegexIterator[] = {
    2264                 :         SPL_ME(RecursiveRegexIterator,  __construct,      arginfo_rec_regex_it___construct, ZEND_ACC_PUBLIC)
    2265                 :         SPL_ME(RecursiveFilterIterator, hasChildren,      arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    2266                 :         SPL_ME(RecursiveRegexIterator,  getChildren,      arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    2267                 :         PHP_FE_END
    2268                 : };
    2269                 : #endif
    2270                 : 
    2271              17 : static inline int spl_limit_it_valid(spl_dual_it_object *intern TSRMLS_DC)
    2272                 : {
    2273                 :         /* FAILURE / SUCCESS */
    2274              17 :         if (intern->u.limit.count != -1 && intern->current.pos >= intern->u.limit.offset + intern->u.limit.count) {
    2275               0 :                 return FAILURE;
    2276                 :         } else {
    2277              17 :                 return spl_dual_it_valid(intern TSRMLS_CC);
    2278                 :         }
    2279                 : }
    2280                 : 
    2281              33 : static inline void spl_limit_it_seek(spl_dual_it_object *intern, long pos TSRMLS_DC)
    2282                 : {
    2283                 :         zval  *zpos;
    2284                 : 
    2285              33 :         spl_dual_it_free(intern TSRMLS_CC);
    2286              33 :         if (pos < intern->u.limit.offset) {
    2287               1 :                 zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0 TSRMLS_CC, "Cannot seek to %ld which is below the offset %ld", pos, intern->u.limit.offset);
    2288               1 :                 return;
    2289                 :         }
    2290              32 :         if (pos >= intern->u.limit.offset + intern->u.limit.count && intern->u.limit.count != -1) {
    2291               1 :                 zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0 TSRMLS_CC, "Cannot seek to %ld which is behind offset %ld plus count %ld", pos, intern->u.limit.offset, intern->u.limit.count);
    2292               1 :                 return;
    2293                 :         }
    2294              48 :         if (pos != intern->current.pos && instanceof_function(intern->inner.ce, spl_ce_SeekableIterator TSRMLS_CC)) {
    2295              17 :                 MAKE_STD_ZVAL(zpos);
    2296              17 :                 ZVAL_LONG(zpos, pos);
    2297              17 :                 spl_dual_it_free(intern TSRMLS_CC);
    2298              17 :                 zend_call_method_with_1_params(&intern->inner.zobject, intern->inner.ce, NULL, "seek", NULL, zpos);
    2299              17 :                 zval_ptr_dtor(&zpos);
    2300              17 :                 if (!EG(exception)) {
    2301              17 :                         intern->current.pos = pos;
    2302              17 :                         if (spl_limit_it_valid(intern TSRMLS_CC) == SUCCESS) {
    2303              17 :                                 spl_dual_it_fetch(intern, 0 TSRMLS_CC);
    2304                 :                         }
    2305                 :                 }
    2306                 :         } else {
    2307                 :                 /* emulate the forward seek, by next() calls */
    2308                 :                 /* a back ward seek is done by a previous rewind() */
    2309              14 :                 if (pos < intern->current.pos) {
    2310               1 :                         spl_dual_it_rewind(intern TSRMLS_CC);
    2311                 :                 }
    2312              40 :                 while (pos > intern->current.pos && spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
    2313              12 :                         spl_dual_it_next(intern, 1 TSRMLS_CC);
    2314                 :                 }
    2315              14 :                 if (spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
    2316               9 :                         spl_dual_it_fetch(intern, 1 TSRMLS_CC);
    2317                 :                 }
    2318                 :         }
    2319                 : }
    2320                 : 
    2321                 : /* {{{ proto LimitIterator::__construct(Iterator it [, int offset, int count])
    2322                 :    Construct a LimitIterator from an Iterator with a given starting offset and optionally a maximum count */
    2323              27 : SPL_METHOD(LimitIterator, __construct)
    2324                 : {
    2325              27 :         spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_LimitIterator, zend_ce_iterator, DIT_LimitIterator);
    2326              27 : } /* }}} */
    2327                 : 
    2328                 : /* {{{ proto void LimitIterator::rewind() 
    2329                 :    Rewind the iterator to the specified starting offset */
    2330              27 : SPL_METHOD(LimitIterator, rewind)
    2331                 : {
    2332                 :         spl_dual_it_object   *intern;
    2333                 : 
    2334              27 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    2335              26 :         spl_dual_it_rewind(intern TSRMLS_CC);
    2336              26 :         spl_limit_it_seek(intern, intern->u.limit.offset TSRMLS_CC);
    2337                 : } /* }}} */
    2338                 : 
    2339                 : /* {{{ proto bool LimitIterator::valid()
    2340                 :    Check whether the current element is valid */
    2341              91 : SPL_METHOD(LimitIterator, valid)
    2342                 : {
    2343                 :         spl_dual_it_object   *intern;
    2344                 : 
    2345              91 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    2346                 : 
    2347                 : /*      RETURN_BOOL(spl_limit_it_valid(intern TSRMLS_CC) == SUCCESS);*/
    2348              91 :         RETURN_BOOL((intern->u.limit.count == -1 || intern->current.pos < intern->u.limit.offset + intern->u.limit.count) && intern->current.data);
    2349                 : } /* }}} */
    2350                 : 
    2351                 : /* {{{ proto void LimitIterator::next()
    2352                 :    Move the iterator forward */
    2353              64 : SPL_METHOD(LimitIterator, next)
    2354                 : {
    2355                 :         spl_dual_it_object   *intern;
    2356                 : 
    2357              64 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    2358                 : 
    2359              64 :         spl_dual_it_next(intern, 1 TSRMLS_CC);
    2360              64 :         if (intern->u.limit.count == -1 || intern->current.pos < intern->u.limit.offset + intern->u.limit.count) {
    2361              46 :                 spl_dual_it_fetch(intern, 1 TSRMLS_CC);
    2362                 :         }
    2363                 : } /* }}} */
    2364                 : 
    2365                 : /* {{{ proto void LimitIterator::seek(int position)
    2366                 :    Seek to the given position */
    2367               8 : SPL_METHOD(LimitIterator, seek)
    2368                 : {
    2369                 :         spl_dual_it_object   *intern;
    2370                 :         long                 pos;
    2371                 : 
    2372               8 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &pos) == FAILURE) {
    2373               1 :                 return;
    2374                 :         }
    2375                 : 
    2376               7 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    2377               7 :         spl_limit_it_seek(intern, pos TSRMLS_CC);
    2378               7 :         RETURN_LONG(intern->current.pos);
    2379                 : } /* }}} */
    2380                 : 
    2381                 : /* {{{ proto int LimitIterator::getPosition()
    2382                 :    Return the current position */
    2383               2 : SPL_METHOD(LimitIterator, getPosition)
    2384                 : {
    2385                 :         spl_dual_it_object   *intern;
    2386               2 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    2387               2 :         RETURN_LONG(intern->current.pos);
    2388                 : } /* }}} */
    2389                 : 
    2390                 : ZEND_BEGIN_ARG_INFO(arginfo_seekable_it_seek, 0) 
    2391                 :         ZEND_ARG_INFO(0, position)
    2392                 : ZEND_END_ARG_INFO();
    2393                 : 
    2394                 : static const zend_function_entry spl_funcs_SeekableIterator[] = {
    2395                 :         SPL_ABSTRACT_ME(SeekableIterator, seek, arginfo_seekable_it_seek)
    2396                 :         PHP_FE_END
    2397                 : };
    2398                 : 
    2399                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_limit_it___construct, 0, 0, 1) 
    2400                 :         ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
    2401                 :         ZEND_ARG_INFO(0, offset)
    2402                 :         ZEND_ARG_INFO(0, count)
    2403                 : ZEND_END_ARG_INFO();
    2404                 : 
    2405                 : ZEND_BEGIN_ARG_INFO(arginfo_limit_it_seek, 0) 
    2406                 :         ZEND_ARG_INFO(0, position)
    2407                 : ZEND_END_ARG_INFO();
    2408                 : 
    2409                 : static const zend_function_entry spl_funcs_LimitIterator[] = {
    2410                 :         SPL_ME(LimitIterator,   __construct,      arginfo_limit_it___construct, ZEND_ACC_PUBLIC)
    2411                 :         SPL_ME(LimitIterator,   rewind,           arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    2412                 :         SPL_ME(LimitIterator,   valid,            arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    2413                 :         SPL_ME(dual_it,         key,              arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    2414                 :         SPL_ME(dual_it,         current,          arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    2415                 :         SPL_ME(LimitIterator,   next,             arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    2416                 :         SPL_ME(LimitIterator,   seek,             arginfo_limit_it_seek, ZEND_ACC_PUBLIC)
    2417                 :         SPL_ME(LimitIterator,   getPosition,      arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    2418                 :         SPL_ME(dual_it,         getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    2419                 :         PHP_FE_END
    2420                 : };
    2421                 : 
    2422             647 : static inline int spl_caching_it_valid(spl_dual_it_object *intern TSRMLS_DC)
    2423                 : {
    2424             647 :         return intern->u.caching.flags & CIT_VALID ? SUCCESS : FAILURE;
    2425                 : }
    2426                 : 
    2427             615 : static inline int spl_caching_it_has_next(spl_dual_it_object *intern TSRMLS_DC)
    2428                 : {
    2429             615 :         return spl_dual_it_valid(intern TSRMLS_CC);
    2430                 : }
    2431                 : 
    2432             395 : static inline void spl_caching_it_next(spl_dual_it_object *intern TSRMLS_DC)
    2433                 : {
    2434             395 :         if (spl_dual_it_fetch(intern, 1 TSRMLS_CC) == SUCCESS) {
    2435             287 :                 intern->u.caching.flags |= CIT_VALID;
    2436                 :                 /* Full cache ? */
    2437             287 :                 if (intern->u.caching.flags & CIT_FULL_CACHE) {
    2438                 :                         zval *zcacheval;
    2439                 :                         
    2440              21 :                         MAKE_STD_ZVAL(zcacheval);
    2441              84 :                         ZVAL_ZVAL(zcacheval, intern->current.data, 1, 0);
    2442              21 :                         if (intern->current.key_type == HASH_KEY_IS_LONG) {
    2443              19 :                                 add_index_zval(intern->u.caching.zcache, intern->current.int_key, zcacheval);
    2444                 :                         } else {
    2445               2 :                                 zend_symtable_update(HASH_OF(intern->u.caching.zcache), intern->current.str_key, intern->current.str_key_len, &zcacheval, sizeof(void*), NULL);
    2446                 :                         }
    2447                 :                 }
    2448                 :                 /* Recursion ? */
    2449             287 :                 if (intern->dit_type == DIT_RecursiveCachingIterator) {
    2450                 :                         zval *retval, *zchildren, zflags;
    2451             241 :                         zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "haschildren", &retval);
    2452             241 :                         if (EG(exception)) {
    2453               1 :                                 if (retval) {
    2454               0 :                                         zval_ptr_dtor(&retval);
    2455                 :                                 }
    2456               1 :                                 if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) {
    2457               0 :                                         zend_clear_exception(TSRMLS_C);
    2458                 :                                 } else {
    2459               1 :                                         return;
    2460                 :                                 }
    2461                 :                         } else {
    2462             240 :                                 if (zend_is_true(retval)) {
    2463              73 :                                         zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &zchildren);
    2464              73 :                                         if (EG(exception)) {
    2465               1 :                                                 if (zchildren) {
    2466               0 :                                                         zval_ptr_dtor(&zchildren);
    2467                 :                                                 }
    2468               1 :                                                 if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) {
    2469               0 :                                                         zend_clear_exception(TSRMLS_C);
    2470                 :                                                 } else {
    2471               1 :                                                         zval_ptr_dtor(&retval);
    2472               1 :                                                         return;
    2473                 :                                                 }
    2474                 :                                         } else {
    2475              72 :                                                 INIT_PZVAL(&zflags);
    2476              72 :                                                 ZVAL_LONG(&zflags, intern->u.caching.flags & CIT_PUBLIC);
    2477              72 :                                                 spl_instantiate_arg_ex2(spl_ce_RecursiveCachingIterator, &intern->u.caching.zchildren, 1, zchildren, &zflags TSRMLS_CC);
    2478              72 :                                                 zval_ptr_dtor(&zchildren);
    2479                 :                                         }
    2480                 :                                 }
    2481             239 :                                 zval_ptr_dtor(&retval);
    2482             239 :                                 if (EG(exception)) {
    2483               0 :                                         if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) {
    2484               0 :                                                 zend_clear_exception(TSRMLS_C);
    2485                 :                                         } else {
    2486               0 :                                                 return;
    2487                 :                                         }
    2488                 :                                 }
    2489                 :                         }
    2490                 :                 }
    2491             285 :                 if (intern->u.caching.flags & (CIT_TOSTRING_USE_INNER|CIT_CALL_TOSTRING)) {
    2492                 :                         int  use_copy;
    2493                 :                         zval expr_copy;
    2494              36 :                         ALLOC_ZVAL(intern->u.caching.zstr);
    2495              36 :                         if (intern->u.caching.flags & CIT_TOSTRING_USE_INNER) {
    2496               3 :                                 *intern->u.caching.zstr = *intern->inner.zobject;
    2497                 :                         } else {
    2498              33 :                                 *intern->u.caching.zstr = *intern->current.data;
    2499                 :                         }
    2500              36 :                         zend_make_printable_zval(intern->u.caching.zstr, &expr_copy, &use_copy);
    2501              36 :                         if (use_copy) {
    2502              35 :                                 *intern->u.caching.zstr = expr_copy;
    2503              35 :                                 INIT_PZVAL(intern->u.caching.zstr);
    2504              35 :                                 zval_copy_ctor(intern->u.caching.zstr);
    2505              35 :                                 zval_dtor(&expr_copy);
    2506                 :                         } else {
    2507               1 :                                 INIT_PZVAL(intern->u.caching.zstr);
    2508               1 :                                 zval_copy_ctor(intern->u.caching.zstr);
    2509                 :                         }
    2510                 :                 }
    2511             285 :                 spl_dual_it_next(intern, 0 TSRMLS_CC);  
    2512                 :         } else {
    2513             108 :                 intern->u.caching.flags &= ~CIT_VALID;
    2514                 :         }
    2515                 : }
    2516                 : 
    2517             115 : static inline void spl_caching_it_rewind(spl_dual_it_object *intern TSRMLS_DC)
    2518                 : {
    2519             115 :         spl_dual_it_rewind(intern TSRMLS_CC);
    2520             115 :         zend_hash_clean(HASH_OF(intern->u.caching.zcache));
    2521             115 :         spl_caching_it_next(intern TSRMLS_CC);
    2522             115 : }
    2523                 : 
    2524                 : /* {{{ proto void CachingIterator::__construct(Iterator it [, flags = CIT_CALL_TOSTRING])
    2525                 :    Construct a CachingIterator from an Iterator */
    2526              32 : SPL_METHOD(CachingIterator, __construct)
    2527                 : {
    2528              32 :         spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_CachingIterator, zend_ce_iterator, DIT_CachingIterator);
    2529              32 : } /* }}} */
    2530                 : 
    2531                 : /* {{{ proto void CachingIterator::rewind()
    2532                 :    Rewind the iterator */
    2533             117 : SPL_METHOD(CachingIterator, rewind)
    2534                 : {
    2535                 :         spl_dual_it_object   *intern;
    2536                 :         
    2537             117 :         if (zend_parse_parameters_none() == FAILURE) {
    2538               0 :                 return;
    2539                 :         }
    2540                 : 
    2541             117 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    2542                 : 
    2543             115 :         spl_caching_it_rewind(intern TSRMLS_CC);
    2544                 : } /* }}} */
    2545                 : 
    2546                 : /* {{{ proto bool CachingIterator::valid()
    2547                 :    Check whether the current element is valid */
    2548             647 : SPL_METHOD(CachingIterator, valid)
    2549                 : {
    2550                 :         spl_dual_it_object   *intern;
    2551                 :         
    2552             647 :         if (zend_parse_parameters_none() == FAILURE) {
    2553               0 :                 return;
    2554                 :         }
    2555                 : 
    2556             647 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    2557                 : 
    2558             647 :         RETURN_BOOL(spl_caching_it_valid(intern TSRMLS_CC) == SUCCESS);
    2559                 : } /* }}} */
    2560                 : 
    2561                 : /* {{{ proto void CachingIterator::next()
    2562                 :    Move the iterator forward */
    2563             280 : SPL_METHOD(CachingIterator, next)
    2564                 : {
    2565                 :         spl_dual_it_object   *intern;
    2566                 :         
    2567             280 :         if (zend_parse_parameters_none() == FAILURE) {
    2568               0 :                 return;
    2569                 :         }
    2570                 : 
    2571             280 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    2572                 : 
    2573             280 :         spl_caching_it_next(intern TSRMLS_CC);
    2574                 : } /* }}} */
    2575                 : 
    2576                 : /* {{{ proto bool CachingIterator::hasNext()
    2577                 :    Check whether the inner iterator has a valid next element */
    2578             615 : SPL_METHOD(CachingIterator, hasNext)
    2579                 : {
    2580                 :         spl_dual_it_object   *intern;
    2581                 :         
    2582             615 :         if (zend_parse_parameters_none() == FAILURE) {
    2583               0 :                 return;
    2584                 :         }
    2585                 : 
    2586             615 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    2587                 : 
    2588             615 :         RETURN_BOOL(spl_caching_it_has_next(intern TSRMLS_CC) == SUCCESS);
    2589                 : } /* }}} */
    2590                 : 
    2591                 : /* {{{ proto string CachingIterator::__toString()
    2592                 :    Return the string representation of the current element */
    2593              19 : SPL_METHOD(CachingIterator, __toString)
    2594                 : {
    2595                 :         spl_dual_it_object   *intern;
    2596                 : 
    2597              19 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    2598                 : 
    2599              19 :         if (!(intern->u.caching.flags & (CIT_CALL_TOSTRING|CIT_TOSTRING_USE_KEY|CIT_TOSTRING_USE_CURRENT|CIT_TOSTRING_USE_INNER)))       {
    2600               1 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s does not fetch string value (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name);
    2601               1 :                 return;
    2602                 :         }
    2603              18 :         if (intern->u.caching.flags & CIT_TOSTRING_USE_KEY) {
    2604               6 :                 if (intern->current.key_type == HASH_KEY_IS_STRING) {
    2605               2 :                         RETURN_STRINGL(intern->current.str_key, intern->current.str_key_len-1, 1);
    2606                 :                 } else {
    2607               4 :                         RETVAL_LONG(intern->current.int_key);
    2608               4 :                         convert_to_string(return_value);
    2609               4 :                         return;
    2610                 :                 }
    2611              12 :         } else if (intern->u.caching.flags & CIT_TOSTRING_USE_CURRENT) {
    2612               3 :                 MAKE_COPY_ZVAL(&intern->current.data, return_value);
    2613               3 :                 convert_to_string(return_value);
    2614               3 :                 return;
    2615                 :         }
    2616               9 :         if (intern->u.caching.zstr) {
    2617               8 :                 RETURN_STRINGL(Z_STRVAL_P(intern->u.caching.zstr), Z_STRLEN_P(intern->u.caching.zstr), 1);
    2618                 :         } else {
    2619               1 :                 RETURN_NULL();
    2620                 :         }
    2621                 : } /* }}} */
    2622                 : 
    2623                 : /* {{{ proto void CachingIterator::offsetSet(mixed index, mixed newval)
    2624                 :    Set given index in cache */
    2625              12 : SPL_METHOD(CachingIterator, offsetSet)
    2626                 : {
    2627                 :         spl_dual_it_object   *intern;
    2628                 :         char *arKey;
    2629                 :         uint nKeyLength;
    2630                 :         zval *value;
    2631                 : 
    2632              12 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    2633                 : 
    2634              12 :         if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
    2635               1 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name);
    2636               1 :                 return;
    2637                 :         }
    2638                 : 
    2639              11 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &arKey, &nKeyLength, &value) == FAILURE) {
    2640               2 :                 return;
    2641                 :         }
    2642                 : 
    2643               9 :         Z_ADDREF_P(value);
    2644               9 :         zend_symtable_update(HASH_OF(intern->u.caching.zcache), arKey, nKeyLength+1, &value, sizeof(value), NULL);
    2645                 : }
    2646                 : /* }}} */
    2647                 : 
    2648                 : /* {{{ proto string CachingIterator::offsetGet(mixed index)
    2649                 :    Return the internal cache if used */
    2650              22 : SPL_METHOD(CachingIterator, offsetGet)
    2651                 : {
    2652                 :         spl_dual_it_object   *intern;
    2653                 :         char *arKey;
    2654                 :         uint nKeyLength;
    2655                 :         zval **value;
    2656                 : 
    2657              22 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    2658                 : 
    2659              22 :         if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
    2660               1 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name);
    2661               1 :                 return;
    2662                 :         }
    2663                 : 
    2664              21 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arKey, &nKeyLength) == FAILURE) {
    2665               3 :                 return;
    2666                 :         }
    2667                 : 
    2668              18 :         if (zend_symtable_find(HASH_OF(intern->u.caching.zcache), arKey, nKeyLength+1, (void**)&value) == FAILURE) {
    2669               8 :                 zend_error(E_NOTICE, "Undefined index:  %s", arKey);
    2670               8 :                 return;
    2671                 :         }
    2672                 :         
    2673              30 :         RETURN_ZVAL(*value, 1, 0);
    2674                 : }
    2675                 : /* }}} */
    2676                 : 
    2677                 : /* {{{ proto void CachingIterator::offsetUnset(mixed index)
    2678                 :    Unset given index in cache */
    2679               9 : SPL_METHOD(CachingIterator, offsetUnset)
    2680                 : {
    2681                 :         spl_dual_it_object   *intern;
    2682                 :         char *arKey;
    2683                 :         uint nKeyLength;
    2684                 : 
    2685               9 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    2686                 : 
    2687               9 :         if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
    2688               1 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name);
    2689               1 :                 return;
    2690                 :         }
    2691                 : 
    2692               8 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arKey, &nKeyLength) == FAILURE) {
    2693               1 :                 return;
    2694                 :         }
    2695                 : 
    2696               7 :         zend_symtable_del(HASH_OF(intern->u.caching.zcache), arKey, nKeyLength+1);
    2697                 : }
    2698                 : /* }}} */
    2699                 : 
    2700                 : /* {{{ proto bool CachingIterator::offsetExists(mixed index)
    2701                 :    Return whether the requested index exists */
    2702              29 : SPL_METHOD(CachingIterator, offsetExists)
    2703                 : {
    2704                 :         spl_dual_it_object   *intern;
    2705                 :         char *arKey;
    2706                 :         uint nKeyLength;
    2707                 :         
    2708              29 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    2709                 : 
    2710              29 :         if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
    2711               1 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name);
    2712               1 :                 return;
    2713                 :         }
    2714                 :         
    2715              28 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arKey, &nKeyLength) == FAILURE) {
    2716               3 :                 return;
    2717                 :         }
    2718                 : 
    2719              25 :         RETURN_BOOL(zend_symtable_exists(HASH_OF(intern->u.caching.zcache), arKey, nKeyLength+1));
    2720                 : }
    2721                 : /* }}} */
    2722                 : 
    2723                 : /* {{{ proto bool CachingIterator::getCache()
    2724                 :    Return the cache */
    2725               6 : SPL_METHOD(CachingIterator, getCache)
    2726                 : {
    2727                 :         spl_dual_it_object   *intern;
    2728                 :         
    2729               6 :         if (zend_parse_parameters_none() == FAILURE) {
    2730               0 :                 return;
    2731                 :         }
    2732                 :         
    2733               6 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    2734                 : 
    2735               6 :         if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
    2736               1 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%v does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name);
    2737               1 :                 return;
    2738                 :         }
    2739                 : 
    2740              15 :         RETURN_ZVAL(intern->u.caching.zcache, 1, 0);
    2741                 : }
    2742                 : /* }}} */
    2743                 : 
    2744                 : /* {{{ proto int CachingIterator::getFlags()
    2745                 :    Return the internal flags */
    2746               9 : SPL_METHOD(CachingIterator, getFlags)
    2747                 : {
    2748                 :         spl_dual_it_object   *intern;
    2749                 : 
    2750               9 :         if (zend_parse_parameters_none() == FAILURE) {
    2751               0 :                 return;
    2752                 :         }
    2753                 :         
    2754               9 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    2755                 : 
    2756               9 :         RETURN_LONG(intern->u.caching.flags);
    2757                 : }
    2758                 : /* }}} */
    2759                 : 
    2760                 : /* {{{ proto void CachingIterator::setFlags(int flags)
    2761                 :    Set the internal flags */
    2762              12 : SPL_METHOD(CachingIterator, setFlags)
    2763                 : {
    2764                 :         spl_dual_it_object   *intern;
    2765                 :         long flags;
    2766                 : 
    2767              12 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    2768                 : 
    2769              12 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &flags) == FAILURE) {
    2770               1 :                 return;
    2771                 :         }
    2772                 : 
    2773              11 :         if (spl_cit_check_flags(flags) != SUCCESS) {
    2774               5 :                 zend_throw_exception(spl_ce_InvalidArgumentException , "Flags must contain only one of CALL_TOSTRING, TOSTRING_USE_KEY, TOSTRING_USE_CURRENT, TOSTRING_USE_INNER", 0 TSRMLS_CC);
    2775               5 :                 return;
    2776                 :         }
    2777               6 :         if ((intern->u.caching.flags & CIT_CALL_TOSTRING) != 0 && (flags & CIT_CALL_TOSTRING) == 0) {
    2778               1 :                 zend_throw_exception(spl_ce_InvalidArgumentException, "Unsetting flag CALL_TO_STRING is not possible", 0 TSRMLS_CC);
    2779               1 :                 return;
    2780                 :         }
    2781               5 :         if ((intern->u.caching.flags & CIT_TOSTRING_USE_INNER) != 0 && (flags & CIT_TOSTRING_USE_INNER) == 0) {
    2782               1 :                 zend_throw_exception(spl_ce_InvalidArgumentException, "Unsetting flag TOSTRING_USE_INNER is not possible", 0 TSRMLS_CC);
    2783               1 :                 return;
    2784                 :         }
    2785               4 :         if ((flags & CIT_FULL_CACHE) != 0 && (intern->u.caching.flags & CIT_FULL_CACHE) == 0) {
    2786                 :                 /* clear on (re)enable */
    2787               0 :                 zend_hash_clean(HASH_OF(intern->u.caching.zcache));
    2788                 :         }
    2789               4 :         intern->u.caching.flags = (intern->u.caching.flags & ~CIT_PUBLIC) | (flags & CIT_PUBLIC);
    2790                 : }
    2791                 : /* }}} */
    2792                 : 
    2793                 : /* {{{ proto void CachingIterator::count()
    2794                 :    Number of cached elements */
    2795               6 : SPL_METHOD(CachingIterator, count)
    2796                 : {
    2797                 :         spl_dual_it_object   *intern;
    2798                 : 
    2799               6 :         if (zend_parse_parameters_none() == FAILURE) {
    2800               0 :                 return;
    2801                 :         }
    2802                 :         
    2803               6 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    2804                 : 
    2805               6 :         if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
    2806               1 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%v does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name);
    2807               1 :                 return;
    2808                 :         }
    2809                 : 
    2810               5 :         RETURN_LONG(zend_hash_num_elements(HASH_OF(intern->u.caching.zcache)));
    2811                 : }
    2812                 : /* }}} */
    2813                 : 
    2814                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_caching_it___construct, 0, 0, 1) 
    2815                 :         ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
    2816                 :         ZEND_ARG_INFO(0, flags)
    2817                 : ZEND_END_ARG_INFO();
    2818                 : 
    2819                 : ZEND_BEGIN_ARG_INFO(arginfo_caching_it_setFlags, 0) 
    2820                 :         ZEND_ARG_INFO(0, flags)
    2821                 : ZEND_END_ARG_INFO();
    2822                 : 
    2823                 : ZEND_BEGIN_ARG_INFO(arginfo_caching_it_offsetGet, 0)
    2824                 :         ZEND_ARG_INFO(0, index)
    2825                 : ZEND_END_ARG_INFO();
    2826                 : 
    2827                 : ZEND_BEGIN_ARG_INFO(arginfo_caching_it_offsetSet, 0)
    2828                 :         ZEND_ARG_INFO(0, index)
    2829                 :         ZEND_ARG_INFO(0, newval)
    2830                 : ZEND_END_ARG_INFO();
    2831                 : 
    2832                 : static const zend_function_entry spl_funcs_CachingIterator[] = {
    2833                 :         SPL_ME(CachingIterator, __construct,      arginfo_caching_it___construct, ZEND_ACC_PUBLIC)
    2834                 :         SPL_ME(CachingIterator, rewind,           arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
    2835                 :         SPL_ME(CachingIterator, valid,            arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
    2836                 :         SPL_ME(dual_it,         key,              arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
    2837                 :         SPL_ME(dual_it,         current,          arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
    2838                 :         SPL_ME(CachingIterator, next,             arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
    2839                 :         SPL_ME(CachingIterator, hasNext,          arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
    2840                 :         SPL_ME(CachingIterator, __toString,       arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
    2841                 :         SPL_ME(dual_it,         getInnerIterator, arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
    2842                 :         SPL_ME(CachingIterator, getFlags,         arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
    2843                 :         SPL_ME(CachingIterator, setFlags,         arginfo_caching_it_setFlags,    ZEND_ACC_PUBLIC)
    2844                 :         SPL_ME(CachingIterator, offsetGet,        arginfo_caching_it_offsetGet,   ZEND_ACC_PUBLIC)
    2845                 :         SPL_ME(CachingIterator, offsetSet,        arginfo_caching_it_offsetSet,   ZEND_ACC_PUBLIC)
    2846                 :         SPL_ME(CachingIterator, offsetUnset,      arginfo_caching_it_offsetGet,   ZEND_ACC_PUBLIC)
    2847                 :         SPL_ME(CachingIterator, offsetExists,     arginfo_caching_it_offsetGet,   ZEND_ACC_PUBLIC)
    2848                 :         SPL_ME(CachingIterator, getCache,         arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
    2849                 :         SPL_ME(CachingIterator, count,            arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
    2850                 :         PHP_FE_END
    2851                 : };
    2852                 : 
    2853                 : /* {{{ proto void RecursiveCachingIterator::__construct(RecursiveIterator it [, flags = CIT_CALL_TOSTRING])
    2854                 :    Create an iterator from a RecursiveIterator */
    2855             100 : SPL_METHOD(RecursiveCachingIterator, __construct)
    2856                 : {
    2857             100 :         spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveCachingIterator, spl_ce_RecursiveIterator, DIT_RecursiveCachingIterator);
    2858             100 : } /* }}} */
    2859                 : 
    2860                 : /* {{{ proto bool RecursiveCachingIterator::hasChildren()
    2861                 :    Check whether the current element of the inner iterator has children */
    2862             238 : SPL_METHOD(RecursiveCachingIterator, hasChildren)
    2863                 : {
    2864                 :         spl_dual_it_object   *intern;
    2865                 : 
    2866             238 :         if (zend_parse_parameters_none() == FAILURE) {
    2867               0 :                 return;
    2868                 :         }
    2869                 :         
    2870             238 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    2871                 : 
    2872             238 :         RETURN_BOOL(intern->u.caching.zchildren);
    2873                 : } /* }}} */
    2874                 : 
    2875                 : /* {{{ proto RecursiveCachingIterator RecursiveCachingIterator::getChildren()
    2876                 :   Return the inner iterator's children as a RecursiveCachingIterator */
    2877              73 : SPL_METHOD(RecursiveCachingIterator, getChildren)
    2878                 : {
    2879                 :         spl_dual_it_object   *intern;
    2880                 :         
    2881              73 :         if (zend_parse_parameters_none() == FAILURE) {
    2882               0 :                 return;
    2883                 :         }
    2884                 : 
    2885              73 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    2886                 : 
    2887              73 :         if (intern->u.caching.zchildren) {
    2888             213 :                 RETURN_ZVAL(intern->u.caching.zchildren, 1, 0);
    2889                 :         } else {
    2890               2 :                 RETURN_NULL();
    2891                 :         }
    2892                 : } /* }}} */
    2893                 : 
    2894                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_caching_rec_it___construct, 0, ZEND_RETURN_VALUE, 1) 
    2895                 :         ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
    2896                 :         ZEND_ARG_INFO(0, flags)
    2897                 : ZEND_END_ARG_INFO();
    2898                 : 
    2899                 : static const zend_function_entry spl_funcs_RecursiveCachingIterator[] = {
    2900                 :         SPL_ME(RecursiveCachingIterator, __construct,   arginfo_caching_rec_it___construct, ZEND_ACC_PUBLIC)
    2901                 :         SPL_ME(RecursiveCachingIterator, hasChildren,   arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    2902                 :         SPL_ME(RecursiveCachingIterator, getChildren,   arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    2903                 :         PHP_FE_END
    2904                 : };
    2905                 : 
    2906                 : /* {{{ proto void IteratorIterator::__construct(Traversable it)
    2907                 :    Create an iterator from anything that is traversable */
    2908              25 : SPL_METHOD(IteratorIterator, __construct)
    2909                 : {
    2910              25 :         spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_IteratorIterator, zend_ce_traversable, DIT_IteratorIterator);
    2911              25 : } /* }}} */
    2912                 : 
    2913                 : ZEND_BEGIN_ARG_INFO(arginfo_iterator_it___construct, 0) 
    2914                 :         ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
    2915                 : ZEND_END_ARG_INFO();
    2916                 : 
    2917                 : static const zend_function_entry spl_funcs_IteratorIterator[] = {
    2918                 :         SPL_ME(IteratorIterator, __construct,      arginfo_iterator_it___construct, ZEND_ACC_PUBLIC)
    2919                 :         SPL_ME(dual_it,          rewind,           arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    2920                 :         SPL_ME(dual_it,          valid,            arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    2921                 :         SPL_ME(dual_it,          key,              arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    2922                 :         SPL_ME(dual_it,          current,          arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    2923                 :         SPL_ME(dual_it,          next,             arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    2924                 :         SPL_ME(dual_it,          getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    2925                 :         PHP_FE_END
    2926                 : };
    2927                 : 
    2928                 : /* {{{ proto void NoRewindIterator::__construct(Iterator it)
    2929                 :    Create an iterator from another iterator */
    2930              10 : SPL_METHOD(NoRewindIterator, __construct)
    2931                 : {
    2932              10 :         spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_NoRewindIterator, zend_ce_iterator, DIT_NoRewindIterator);
    2933              10 : } /* }}} */
    2934                 : 
    2935                 : /* {{{ proto void NoRewindIterator::rewind()
    2936                 :    Prevent a call to inner iterators rewind() */
    2937              11 : SPL_METHOD(NoRewindIterator, rewind)
    2938                 : {
    2939              11 :         if (zend_parse_parameters_none() == FAILURE) {
    2940               0 :                 return;
    2941                 :         }
    2942                 :         /* nothing to do */
    2943                 : } /* }}} */
    2944                 : 
    2945                 : /* {{{ proto bool NoRewindIterator::valid()
    2946                 :    Return inner iterators valid() */
    2947              30 : SPL_METHOD(NoRewindIterator, valid)
    2948                 : {
    2949                 :         spl_dual_it_object   *intern;
    2950                 :         
    2951              30 :         if (zend_parse_parameters_none() == FAILURE) {
    2952               0 :                 return;
    2953                 :         }
    2954                 : 
    2955              30 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    2956              29 :         RETURN_BOOL(intern->inner.iterator->funcs->valid(intern->inner.iterator TSRMLS_CC) == SUCCESS);
    2957                 : } /* }}} */
    2958                 : 
    2959                 : /* {{{ proto mixed NoRewindIterator::key()
    2960                 :    Return inner iterators key() */
    2961              16 : SPL_METHOD(NoRewindIterator, key)
    2962                 : {
    2963                 :         spl_dual_it_object   *intern;
    2964                 :         
    2965              16 :         if (zend_parse_parameters_none() == FAILURE) {
    2966               0 :                 return;
    2967                 :         }
    2968                 : 
    2969              16 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    2970                 : 
    2971              16 :         if (intern->inner.iterator->funcs->get_current_key) {
    2972                 :                 char *str_key;
    2973                 :                 uint str_key_len;
    2974                 :                 ulong int_key;
    2975              16 :                 switch (intern->inner.iterator->funcs->get_current_key(intern->inner.iterator, &str_key, &str_key_len, &int_key TSRMLS_CC)) {
    2976                 :                         case HASH_KEY_IS_LONG:
    2977              14 :                                 RETURN_LONG(int_key);
    2978                 :                                 break;
    2979                 :                         case HASH_KEY_IS_STRING:
    2980               2 :                                 RETURN_STRINGL(str_key, str_key_len-1, 0);
    2981                 :                                 break;
    2982                 :                         default:
    2983               0 :                                 RETURN_NULL();
    2984                 :                 }
    2985                 :         } else {
    2986               0 :                 RETURN_NULL();
    2987                 :         }
    2988                 : } /* }}} */
    2989                 : 
    2990                 : /* {{{ proto mixed NoRewindIterator::current()
    2991                 :    Return inner iterators current() */
    2992              21 : SPL_METHOD(NoRewindIterator, current)
    2993                 : {
    2994                 :         spl_dual_it_object   *intern;
    2995                 :         zval **data;
    2996                 :         
    2997              21 :         if (zend_parse_parameters_none() == FAILURE) {
    2998               0 :                 return;
    2999                 :         }
    3000                 : 
    3001              21 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    3002              21 :         intern->inner.iterator->funcs->get_current_data(intern->inner.iterator, &data TSRMLS_CC);
    3003              21 :         if (data && *data) {
    3004              63 :                 RETURN_ZVAL(*data, 1, 0);
    3005                 :         }
    3006                 : } /* }}} */
    3007                 : 
    3008                 : /* {{{ proto void NoRewindIterator::next()
    3009                 :    Return inner iterators next() */
    3010              20 : SPL_METHOD(NoRewindIterator, next)
    3011                 : {
    3012                 :         spl_dual_it_object   *intern;
    3013                 :         
    3014              20 :         if (zend_parse_parameters_none() == FAILURE) {
    3015               0 :                 return;
    3016                 :         }
    3017                 : 
    3018              20 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    3019              20 :         intern->inner.iterator->funcs->move_forward(intern->inner.iterator TSRMLS_CC);
    3020                 : } /* }}} */
    3021                 : 
    3022                 : ZEND_BEGIN_ARG_INFO(arginfo_norewind_it___construct, 0) 
    3023                 :         ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
    3024                 : ZEND_END_ARG_INFO();
    3025                 : 
    3026                 : static const zend_function_entry spl_funcs_NoRewindIterator[] = {
    3027                 :         SPL_ME(NoRewindIterator, __construct,      arginfo_norewind_it___construct, ZEND_ACC_PUBLIC)
    3028                 :         SPL_ME(NoRewindIterator, rewind,           arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    3029                 :         SPL_ME(NoRewindIterator, valid,            arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    3030                 :         SPL_ME(NoRewindIterator, key,              arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    3031                 :         SPL_ME(NoRewindIterator, current,          arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    3032                 :         SPL_ME(NoRewindIterator, next,             arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    3033                 :         SPL_ME(dual_it,          getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    3034                 :         PHP_FE_END
    3035                 : };
    3036                 : 
    3037                 : /* {{{ proto void InfiniteIterator::__construct(Iterator it)
    3038                 :    Create an iterator from another iterator */
    3039               7 : SPL_METHOD(InfiniteIterator, __construct)
    3040                 : {
    3041               7 :         spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_InfiniteIterator, zend_ce_iterator, DIT_InfiniteIterator);
    3042               7 : } /* }}} */
    3043                 : 
    3044                 : /* {{{ proto void InfiniteIterator::next()
    3045                 :    Prevent a call to inner iterators rewind() (internally the current data will be fetched if valid()) */
    3046              34 : SPL_METHOD(InfiniteIterator, next)
    3047                 : {
    3048                 :         spl_dual_it_object   *intern;
    3049                 :         
    3050              34 :         if (zend_parse_parameters_none() == FAILURE) {
    3051               0 :                 return;
    3052                 :         }
    3053                 : 
    3054              34 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    3055                 : 
    3056              34 :         spl_dual_it_next(intern, 1 TSRMLS_CC);
    3057              34 :         if (spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
    3058              24 :                 spl_dual_it_fetch(intern, 0 TSRMLS_CC);
    3059                 :         } else {
    3060              10 :                 spl_dual_it_rewind(intern TSRMLS_CC);
    3061              10 :                 if (spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
    3062              10 :                         spl_dual_it_fetch(intern, 0 TSRMLS_CC);
    3063                 :                 }
    3064                 :         }
    3065                 : } /* }}} */
    3066                 : 
    3067                 : static const zend_function_entry spl_funcs_InfiniteIterator[] = {
    3068                 :         SPL_ME(InfiniteIterator, __construct,      arginfo_norewind_it___construct, ZEND_ACC_PUBLIC)
    3069                 :         SPL_ME(InfiniteIterator, next,             arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    3070                 :         PHP_FE_END
    3071                 : };
    3072                 : 
    3073                 : /* {{{ proto void EmptyIterator::rewind()
    3074                 :    Does nothing  */
    3075               6 : SPL_METHOD(EmptyIterator, rewind)
    3076                 : {
    3077               6 :         if (zend_parse_parameters_none() == FAILURE) {
    3078               0 :                 return;
    3079                 :         }
    3080                 : } /* }}} */
    3081                 : 
    3082                 : /* {{{ proto false EmptyIterator::valid()
    3083                 :    Return false */
    3084               9 : SPL_METHOD(EmptyIterator, valid)
    3085                 : {
    3086               9 :         if (zend_parse_parameters_none() == FAILURE) {
    3087               0 :                 return;
    3088                 :         }
    3089               9 :         RETURN_FALSE;
    3090                 : } /* }}} */
    3091                 : 
    3092                 : /* {{{ proto void EmptyIterator::key()
    3093                 :    Throws exception BadMethodCallException */
    3094               1 : SPL_METHOD(EmptyIterator, key)
    3095                 : {
    3096               1 :         if (zend_parse_parameters_none() == FAILURE) {
    3097               0 :                 return;
    3098                 :         }
    3099               1 :         zend_throw_exception(spl_ce_BadMethodCallException, "Accessing the key of an EmptyIterator", 0 TSRMLS_CC);
    3100                 : } /* }}} */
    3101                 : 
    3102                 : /* {{{ proto void EmptyIterator::current()
    3103                 :    Throws exception BadMethodCallException */
    3104               1 : SPL_METHOD(EmptyIterator, current)
    3105                 : {
    3106               1 :         if (zend_parse_parameters_none() == FAILURE) {
    3107               0 :                 return;
    3108                 :         }
    3109               1 :         zend_throw_exception(spl_ce_BadMethodCallException, "Accessing the value of an EmptyIterator", 0 TSRMLS_CC);
    3110                 : } /* }}} */
    3111                 : 
    3112                 : /* {{{ proto void EmptyIterator::next()
    3113                 :    Does nothing */
    3114               1 : SPL_METHOD(EmptyIterator, next)
    3115                 : {
    3116               1 :         if (zend_parse_parameters_none() == FAILURE) {
    3117               0 :                 return;
    3118                 :         }
    3119                 : } /* }}} */
    3120                 : 
    3121                 : static const zend_function_entry spl_funcs_EmptyIterator[] = {
    3122                 :         SPL_ME(EmptyIterator, rewind,           arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    3123                 :         SPL_ME(EmptyIterator, valid,            arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    3124                 :         SPL_ME(EmptyIterator, key,              arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    3125                 :         SPL_ME(EmptyIterator, current,          arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    3126                 :         SPL_ME(EmptyIterator, next,             arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    3127                 :         PHP_FE_END
    3128                 : };
    3129                 : 
    3130              43 : int spl_append_it_next_iterator(spl_dual_it_object *intern TSRMLS_DC) /* {{{*/
    3131                 : {
    3132              43 :         spl_dual_it_free(intern TSRMLS_CC);
    3133                 : 
    3134              43 :         if (intern->inner.zobject) {
    3135              27 :                 zval_ptr_dtor(&intern->inner.zobject);
    3136              27 :                 intern->inner.zobject = NULL;
    3137              27 :                 intern->inner.ce = NULL;
    3138              27 :                 intern->inner.object = NULL;
    3139              27 :                 if (intern->inner.iterator) {
    3140              27 :                         intern->inner.iterator->funcs->dtor(intern->inner.iterator TSRMLS_CC);
    3141              27 :                         intern->inner.iterator = NULL;
    3142                 :                 }
    3143                 :         }
    3144              43 :         if (intern->u.append.iterator->funcs->valid(intern->u.append.iterator TSRMLS_CC) == SUCCESS) {
    3145                 :                 zval **it;
    3146                 : 
    3147              27 :                 intern->u.append.iterator->funcs->get_current_data(intern->u.append.iterator, &it TSRMLS_CC);
    3148              27 :                 Z_ADDREF_PP(it);
    3149              27 :                 intern->inner.zobject = *it;
    3150              27 :                 intern->inner.ce = Z_OBJCE_PP(it);
    3151              27 :                 intern->inner.object = zend_object_store_get_object(*it TSRMLS_CC);
    3152              27 :                 intern->inner.iterator = intern->inner.ce->get_iterator(intern->inner.ce, *it, 0 TSRMLS_CC);
    3153              27 :                 spl_dual_it_rewind(intern TSRMLS_CC);
    3154              27 :                 return SUCCESS;
    3155                 :         } else {
    3156              16 :                 return FAILURE;
    3157                 :         }
    3158                 : } /* }}} */
    3159                 : 
    3160              63 : void spl_append_it_fetch(spl_dual_it_object *intern TSRMLS_DC) /* {{{*/
    3161                 : {
    3162             135 :         while (spl_dual_it_valid(intern TSRMLS_CC) != SUCCESS) {
    3163              23 :                 intern->u.append.iterator->funcs->move_forward(intern->u.append.iterator TSRMLS_CC);
    3164              23 :                 if (spl_append_it_next_iterator(intern TSRMLS_CC) != SUCCESS) {
    3165              14 :                         return;
    3166                 :                 }
    3167                 :         }
    3168              49 :         spl_dual_it_fetch(intern, 0 TSRMLS_CC);
    3169                 : } /* }}} */
    3170                 : 
    3171              45 : void spl_append_it_next(spl_dual_it_object *intern TSRMLS_DC) /* {{{ */
    3172                 : {
    3173              45 :         if (spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
    3174              44 :                 spl_dual_it_next(intern, 1 TSRMLS_CC);
    3175                 :         }
    3176              45 :         spl_append_it_fetch(intern TSRMLS_CC);
    3177              45 : } /* }}} */
    3178                 : 
    3179                 : /* {{{ proto void AppendIterator::__construct()
    3180                 :    Create an AppendIterator */
    3181               9 : SPL_METHOD(AppendIterator, __construct)
    3182                 : {
    3183               9 :         spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_AppendIterator, zend_ce_iterator, DIT_AppendIterator);
    3184               9 : } /* }}} */
    3185                 : 
    3186                 : /* {{{ proto void AppendIterator::append(Iterator it)
    3187                 :    Append an iterator */
    3188              14 : SPL_METHOD(AppendIterator, append)
    3189                 : {
    3190                 :         spl_dual_it_object   *intern;
    3191                 :         zval *it;
    3192                 : 
    3193              14 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    3194                 : 
    3195              13 :         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "O", &it, zend_ce_iterator) == FAILURE) {
    3196               1 :                 return;
    3197                 :         }
    3198              12 :         spl_array_iterator_append(intern->u.append.zarrayit, it TSRMLS_CC);
    3199                 : 
    3200              12 :         if (!intern->inner.iterator || spl_dual_it_valid(intern TSRMLS_CC) != SUCCESS) {
    3201               7 :                 if (intern->u.append.iterator->funcs->valid(intern->u.append.iterator TSRMLS_CC) != SUCCESS) {
    3202               0 :                         intern->u.append.iterator->funcs->rewind(intern->u.append.iterator TSRMLS_CC);
    3203                 :                 }
    3204                 :                 do {
    3205               7 :                         spl_append_it_next_iterator(intern TSRMLS_CC);
    3206               7 :                 } while (intern->inner.zobject != it);
    3207               7 :                 spl_append_it_fetch(intern TSRMLS_CC);
    3208                 :         }
    3209                 : } /* }}} */
    3210                 : 
    3211                 : /* {{{ proto void AppendIterator::rewind()
    3212                 :    Rewind to the first iterator and rewind the first iterator, too */
    3213              14 : SPL_METHOD(AppendIterator, rewind)
    3214                 : {
    3215                 :         spl_dual_it_object   *intern;
    3216                 :         
    3217              14 :         if (zend_parse_parameters_none() == FAILURE) {
    3218               0 :                 return;
    3219                 :         }
    3220                 : 
    3221              14 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    3222                 :         
    3223              13 :         intern->u.append.iterator->funcs->rewind(intern->u.append.iterator TSRMLS_CC);
    3224              13 :         if (spl_append_it_next_iterator(intern TSRMLS_CC) == SUCCESS) {
    3225              11 :                 spl_append_it_fetch(intern TSRMLS_CC);
    3226                 :         }
    3227                 : } /* }}} */
    3228                 : 
    3229                 : /* {{{ proto bool AppendIterator::valid()
    3230                 :    Check if the current state is valid */
    3231              59 : SPL_METHOD(AppendIterator, valid)
    3232                 : {
    3233                 :         spl_dual_it_object   *intern;
    3234                 : 
    3235              59 :         if (zend_parse_parameters_none() == FAILURE) {
    3236               0 :                 return;
    3237                 :         }
    3238                 :         
    3239              59 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    3240                 : 
    3241              59 :         RETURN_BOOL(intern->current.data);
    3242                 : } /* }}} */
    3243                 : 
    3244                 : /* {{{ proto void AppendIterator::next()
    3245                 :    Forward to next element */
    3246              45 : SPL_METHOD(AppendIterator, next)
    3247                 : {
    3248                 :         spl_dual_it_object   *intern;
    3249                 :         
    3250              45 :         if (zend_parse_parameters_none() == FAILURE) {
    3251               0 :                 return;
    3252                 :         }
    3253                 : 
    3254              45 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    3255                 :         
    3256              45 :         spl_append_it_next(intern TSRMLS_CC);
    3257                 : } /* }}} */
    3258                 : 
    3259                 : /* {{{ proto int AppendIterator::getIteratorIndex()
    3260                 :    Get index of iterator */
    3261               6 : SPL_METHOD(AppendIterator, getIteratorIndex)
    3262                 : {
    3263                 :         spl_dual_it_object   *intern;
    3264                 :         
    3265               6 :         if (zend_parse_parameters_none() == FAILURE) {
    3266               0 :                 return;
    3267                 :         }
    3268                 : 
    3269               6 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    3270                 : 
    3271               6 :         APPENDIT_CHECK_CTOR(intern);
    3272               6 :         spl_array_iterator_key(intern->u.append.zarrayit, return_value TSRMLS_CC);
    3273                 : } /* }}} */
    3274                 : 
    3275                 : /* {{{ proto ArrayIterator AppendIterator::getArrayIterator()
    3276                 :    Get access to inner ArrayIterator */
    3277               2 : SPL_METHOD(AppendIterator, getArrayIterator)
    3278                 : {
    3279                 :         spl_dual_it_object   *intern;
    3280                 :         
    3281               2 :         if (zend_parse_parameters_none() == FAILURE) {
    3282               0 :                 return;
    3283                 :         }
    3284                 : 
    3285               2 :         SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
    3286                 : 
    3287               6 :         RETURN_ZVAL(intern->u.append.zarrayit, 1, 0);
    3288                 : } /* }}} */
    3289                 : 
    3290                 : ZEND_BEGIN_ARG_INFO(arginfo_append_it_append, 0) 
    3291                 :         ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
    3292                 : ZEND_END_ARG_INFO();
    3293                 : 
    3294                 : static const zend_function_entry spl_funcs_AppendIterator[] = {
    3295                 :         SPL_ME(AppendIterator, __construct,      arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    3296                 :         SPL_ME(AppendIterator, append,           arginfo_append_it_append, ZEND_ACC_PUBLIC)
    3297                 :         SPL_ME(AppendIterator, rewind,           arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    3298                 :         SPL_ME(AppendIterator, valid,            arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    3299                 :         SPL_ME(dual_it,        key,              arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    3300                 :         SPL_ME(dual_it,        current,          arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    3301                 :         SPL_ME(AppendIterator, next,             arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    3302                 :         SPL_ME(dual_it,        getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    3303                 :         SPL_ME(AppendIterator, getIteratorIndex, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    3304                 :         SPL_ME(AppendIterator, getArrayIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
    3305                 :         PHP_FE_END
    3306                 : };
    3307                 : 
    3308              68 : PHPAPI int spl_iterator_apply(zval *obj, spl_iterator_apply_func_t apply_func, void *puser TSRMLS_DC)
    3309                 : {
    3310                 :         zend_object_iterator   *iter;
    3311              68 :         zend_class_entry       *ce = Z_OBJCE_P(obj);
    3312                 : 
    3313              68 :         iter = ce->get_iterator(ce, obj, 0 TSRMLS_CC);
    3314                 : 
    3315              68 :         if (EG(exception)) {
    3316               1 :                 goto done;
    3317                 :         }
    3318                 : 
    3319              67 :         iter->index = 0;
    3320              67 :         if (iter->funcs->rewind) {
    3321              65 :                 iter->funcs->rewind(iter TSRMLS_CC);
    3322              65 :                 if (EG(exception)) {
    3323               5 :                         goto done;
    3324                 :                 }
    3325                 :         }
    3326                 : 
    3327            3319 :         while (iter->funcs->valid(iter TSRMLS_CC) == SUCCESS) {
    3328            3215 :                 if (EG(exception)) {
    3329               0 :                         goto done;
    3330                 :                 }
    3331            3215 :                 if (apply_func(iter, puser TSRMLS_CC) == ZEND_HASH_APPLY_STOP || EG(exception)) {
    3332                 :                         goto done;
    3333                 :                 }
    3334            3199 :                 iter->index++;
    3335            3199 :                 iter->funcs->move_forward(iter TSRMLS_CC);
    3336            3199 :                 if (EG(exception)) {
    3337               4 :                         goto done;
    3338                 :                 }
    3339                 :         }
    3340                 : 
    3341                 : done:
    3342              68 :         if (iter) {
    3343              67 :                 iter->funcs->dtor(iter TSRMLS_CC);
    3344                 :         }
    3345              68 :         return EG(exception) ? FAILURE : SUCCESS;
    3346                 : }
    3347                 : /* }}} */
    3348                 : 
    3349              29 : static int spl_iterator_to_array_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
    3350                 : {
    3351              29 :         zval                    **data, *return_value = (zval*)puser;
    3352                 :         char                    *str_key;
    3353                 :         uint                    str_key_len;
    3354                 :         ulong                   int_key;
    3355                 :         int                     key_type;
    3356                 : 
    3357              29 :         iter->funcs->get_current_data(iter, &data TSRMLS_CC);
    3358              29 :         if (EG(exception)) {
    3359               3 :                 return ZEND_HASH_APPLY_STOP;
    3360                 :         }
    3361              26 :         if (data == NULL || *data == NULL) {
    3362               0 :                 return ZEND_HASH_APPLY_STOP;
    3363                 :         }
    3364              26 :         if (iter->funcs->get_current_key) {
    3365              26 :                 key_type = iter->funcs->get_current_key(iter, &str_key, &str_key_len, &int_key TSRMLS_CC);
    3366              26 :                 if (EG(exception)) {
    3367               2 :                         return ZEND_HASH_APPLY_STOP;
    3368                 :                 }
    3369              24 :                 Z_ADDREF_PP(data);
    3370              24 :                 switch(key_type) {
    3371                 :                         case HASH_KEY_IS_STRING:
    3372               1 :                                 add_assoc_zval_ex(return_value, str_key, str_key_len, *data);
    3373               1 :                                 efree(str_key);
    3374               1 :                                 break;
    3375                 :                         case HASH_KEY_IS_LONG:
    3376              23 :                                 add_index_zval(return_value, int_key, *data);
    3377                 :                                 break;
    3378                 :                 }
    3379                 :         } else {
    3380               0 :                 Z_ADDREF_PP(data);
    3381               0 :                 add_next_index_zval(return_value, *data);
    3382                 :         }
    3383              24 :         return ZEND_HASH_APPLY_KEEP;
    3384                 : }
    3385                 : /* }}} */
    3386                 : 
    3387               7 : static int spl_iterator_to_values_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
    3388                 : {
    3389               7 :         zval **data, *return_value = (zval*)puser;
    3390                 : 
    3391               7 :         iter->funcs->get_current_data(iter, &data TSRMLS_CC);
    3392               7 :         if (EG(exception)) {
    3393               1 :                 return ZEND_HASH_APPLY_STOP;
    3394                 :         }
    3395               6 :         if (data == NULL || *data == NULL) {
    3396               0 :                 return ZEND_HASH_APPLY_STOP;
    3397                 :         }
    3398               6 :         Z_ADDREF_PP(data);
    3399               6 :         add_next_index_zval(return_value, *data);
    3400               6 :         return ZEND_HASH_APPLY_KEEP;
    3401                 : }
    3402                 : /* }}} */
    3403                 : 
    3404                 : /* {{{ proto array iterator_to_array(Traversable it [, bool use_keys = true]) 
    3405                 :    Copy the iterator into an array */
    3406              26 : PHP_FUNCTION(iterator_to_array)
    3407                 : {
    3408                 :         zval  *obj;
    3409              26 :         zend_bool use_keys = 1;
    3410                 : 
    3411              26 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|b", &obj, zend_ce_traversable, &use_keys) == FAILURE) {
    3412               3 :                 RETURN_FALSE;
    3413                 :         }
    3414                 : 
    3415              23 :         array_init(return_value);
    3416                 : 
    3417              23 :         if (spl_iterator_apply(obj, use_keys ? spl_iterator_to_array_apply : spl_iterator_to_values_apply, (void*)return_value TSRMLS_CC) != SUCCESS) {
    3418              13 :                 zval_dtor(return_value);
    3419              13 :                 RETURN_NULL();
    3420                 :         }
    3421                 : } /* }}} */
    3422                 : 
    3423              14 : static int spl_iterator_count_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
    3424                 : {
    3425              14 :         (*(long*)puser)++;
    3426              14 :         return ZEND_HASH_APPLY_KEEP;
    3427                 : }
    3428                 : /* }}} */
    3429                 : 
    3430                 : /* {{{ proto int iterator_count(Traversable it) 
    3431                 :    Count the elements in an iterator */
    3432              13 : PHP_FUNCTION(iterator_count)
    3433                 : {
    3434                 :         zval  *obj;
    3435              13 :         long  count = 0;
    3436                 : 
    3437              13 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, zend_ce_traversable) == FAILURE) {
    3438               2 :                 RETURN_FALSE;
    3439                 :         }
    3440                 :         
    3441              11 :         if (spl_iterator_apply(obj, spl_iterator_count_apply, (void*)&count TSRMLS_CC) == SUCCESS) {
    3442               5 :                 RETURN_LONG(count);
    3443                 :         }
    3444                 : }
    3445                 : /* }}} */
    3446                 : 
    3447                 : typedef struct {
    3448                 :         zval                   *obj;
    3449                 :         zval                   *args;
    3450                 :         long                   count;
    3451                 :         zend_fcall_info        fci;
    3452                 :         zend_fcall_info_cache  fcc;
    3453                 : } spl_iterator_apply_info;
    3454                 : 
    3455              14 : static int spl_iterator_func_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
    3456                 : {
    3457                 :         zval *retval;
    3458              14 :         spl_iterator_apply_info  *apply_info = (spl_iterator_apply_info*)puser;
    3459                 :         int result;
    3460                 : 
    3461              14 :         apply_info->count++;
    3462              14 :         zend_fcall_info_call(&apply_info->fci, &apply_info->fcc, &retval, NULL TSRMLS_CC);
    3463              14 :         if (retval) {
    3464              13 :                 result = zend_is_true(retval) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_STOP;
    3465              13 :                 zval_ptr_dtor(&retval);
    3466                 :         } else {
    3467               1 :                 result = ZEND_HASH_APPLY_STOP;
    3468                 :         }
    3469              14 :         return result;
    3470                 : }
    3471                 : /* }}} */
    3472                 : 
    3473                 : /* {{{ proto int iterator_apply(Traversable it, mixed function [, mixed params])
    3474                 :    Calls a function for every element in an iterator */
    3475               9 : PHP_FUNCTION(iterator_apply)
    3476                 : {
    3477                 :         spl_iterator_apply_info  apply_info;
    3478                 : 
    3479               9 :         apply_info.args = NULL;
    3480               9 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Of|a!", &apply_info.obj, zend_ce_traversable, &apply_info.fci, &apply_info.fcc, &apply_info.args) == FAILURE) {
    3481               3 :                 return;
    3482                 :         }
    3483                 : 
    3484               6 :         apply_info.count = 0;
    3485               6 :         zend_fcall_info_args(&apply_info.fci, apply_info.args TSRMLS_CC);
    3486               6 :         if (spl_iterator_apply(apply_info.obj, spl_iterator_func_apply, (void*)&apply_info TSRMLS_CC) == SUCCESS) {
    3487               4 :                 RETVAL_LONG(apply_info.count);
    3488                 :         } else {
    3489               2 :                 RETVAL_FALSE;
    3490                 :         }
    3491               6 :         zend_fcall_info_args(&apply_info.fci, NULL TSRMLS_CC);
    3492                 : }
    3493                 : /* }}} */
    3494                 : 
    3495                 : static const zend_function_entry spl_funcs_OuterIterator[] = {
    3496                 :         SPL_ABSTRACT_ME(OuterIterator, getInnerIterator,   arginfo_recursive_it_void)
    3497                 :         PHP_FE_END
    3498                 : };
    3499                 : 
    3500                 : static const zend_function_entry spl_funcs_Countable[] = {
    3501                 :         SPL_ABSTRACT_ME(Countable, count,   arginfo_recursive_it_void)
    3502                 :         PHP_FE_END
    3503                 : };
    3504                 : 
    3505                 : /* {{{ PHP_MINIT_FUNCTION(spl_iterators)
    3506                 :  */
    3507           19163 : PHP_MINIT_FUNCTION(spl_iterators)
    3508                 : {
    3509           19163 :         REGISTER_SPL_INTERFACE(RecursiveIterator);
    3510           19163 :         REGISTER_SPL_ITERATOR(RecursiveIterator);
    3511                 : 
    3512           19163 :         REGISTER_SPL_STD_CLASS_EX(RecursiveIteratorIterator, spl_RecursiveIteratorIterator_new, spl_funcs_RecursiveIteratorIterator);
    3513           19163 :         REGISTER_SPL_ITERATOR(RecursiveIteratorIterator);
    3514                 : 
    3515           19163 :         memcpy(&spl_handlers_rec_it_it, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
    3516           19163 :         spl_handlers_rec_it_it.get_method = spl_recursive_it_get_method;
    3517           19163 :         spl_handlers_rec_it_it.clone_obj = NULL;
    3518                 : 
    3519           19163 :         memcpy(&spl_handlers_dual_it, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
    3520           19163 :         spl_handlers_dual_it.get_method = spl_dual_it_get_method;
    3521                 :         /*spl_handlers_dual_it.call_method = spl_dual_it_call_method;*/
    3522           19163 :         spl_handlers_dual_it.clone_obj = NULL;
    3523                 :         
    3524           19163 :         spl_ce_RecursiveIteratorIterator->get_iterator = spl_recursive_it_get_iterator;
    3525           19163 :         spl_ce_RecursiveIteratorIterator->iterator_funcs.funcs = &spl_recursive_it_iterator_funcs;
    3526                 : 
    3527           19163 :         REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "LEAVES_ONLY",     RIT_LEAVES_ONLY);
    3528           19163 :         REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "SELF_FIRST",      RIT_SELF_FIRST);
    3529           19163 :         REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "CHILD_FIRST",     RIT_CHILD_FIRST);
    3530           19163 :         REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "CATCH_GET_CHILD", RIT_CATCH_GET_CHILD);
    3531                 : 
    3532           19163 :         REGISTER_SPL_INTERFACE(OuterIterator);
    3533           19163 :         REGISTER_SPL_ITERATOR(OuterIterator);
    3534                 : 
    3535           19163 :         REGISTER_SPL_STD_CLASS_EX(IteratorIterator, spl_dual_it_new, spl_funcs_IteratorIterator);
    3536           19163 :         REGISTER_SPL_ITERATOR(IteratorIterator);
    3537           19163 :         REGISTER_SPL_IMPLEMENTS(IteratorIterator, OuterIterator);
    3538                 : 
    3539           19163 :         REGISTER_SPL_SUB_CLASS_EX(FilterIterator, IteratorIterator, spl_dual_it_new, spl_funcs_FilterIterator);
    3540           19163 :         spl_ce_FilterIterator->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
    3541                 : 
    3542           19163 :         REGISTER_SPL_SUB_CLASS_EX(RecursiveFilterIterator, FilterIterator, spl_dual_it_new, spl_funcs_RecursiveFilterIterator);
    3543           19163 :         REGISTER_SPL_IMPLEMENTS(RecursiveFilterIterator, RecursiveIterator);
    3544                 : 
    3545           19163 :         REGISTER_SPL_SUB_CLASS_EX(ParentIterator, RecursiveFilterIterator, spl_dual_it_new, spl_funcs_ParentIterator);
    3546                 : 
    3547           19163 :         REGISTER_SPL_INTERFACE(Countable);
    3548           19163 :         REGISTER_SPL_INTERFACE(SeekableIterator);
    3549           19163 :         REGISTER_SPL_ITERATOR(SeekableIterator);
    3550                 : 
    3551           19163 :         REGISTER_SPL_SUB_CLASS_EX(LimitIterator, IteratorIterator, spl_dual_it_new, spl_funcs_LimitIterator);
    3552                 : 
    3553           19163 :         REGISTER_SPL_SUB_CLASS_EX(CachingIterator, IteratorIterator, spl_dual_it_new, spl_funcs_CachingIterator);
    3554           19163 :         REGISTER_SPL_IMPLEMENTS(CachingIterator, ArrayAccess);
    3555           19163 :         REGISTER_SPL_IMPLEMENTS(CachingIterator, Countable);
    3556                 : 
    3557           19163 :         REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "CALL_TOSTRING",        CIT_CALL_TOSTRING); 
    3558           19163 :         REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "CATCH_GET_CHILD",      CIT_CATCH_GET_CHILD); 
    3559           19163 :         REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_KEY",     CIT_TOSTRING_USE_KEY);
    3560           19163 :         REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_CURRENT", CIT_TOSTRING_USE_CURRENT);
    3561           19163 :         REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_INNER",   CIT_TOSTRING_USE_INNER);
    3562           19163 :         REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "FULL_CACHE",           CIT_FULL_CACHE); 
    3563                 : 
    3564           19163 :         REGISTER_SPL_SUB_CLASS_EX(RecursiveCachingIterator, CachingIterator, spl_dual_it_new, spl_funcs_RecursiveCachingIterator);
    3565           19163 :         REGISTER_SPL_IMPLEMENTS(RecursiveCachingIterator, RecursiveIterator);
    3566                 :         
    3567           19163 :         REGISTER_SPL_SUB_CLASS_EX(NoRewindIterator, IteratorIterator, spl_dual_it_new, spl_funcs_NoRewindIterator);
    3568                 : 
    3569           19163 :         REGISTER_SPL_SUB_CLASS_EX(AppendIterator, IteratorIterator, spl_dual_it_new, spl_funcs_AppendIterator);
    3570                 : 
    3571           19163 :         REGISTER_SPL_IMPLEMENTS(RecursiveIteratorIterator, OuterIterator);
    3572                 : 
    3573           19163 :         REGISTER_SPL_SUB_CLASS_EX(InfiniteIterator, IteratorIterator, spl_dual_it_new, spl_funcs_InfiniteIterator);
    3574                 : #if HAVE_PCRE || HAVE_BUNDLED_PCRE
    3575           19163 :         REGISTER_SPL_SUB_CLASS_EX(RegexIterator, FilterIterator, spl_dual_it_new, spl_funcs_RegexIterator);
    3576           19163 :         REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "USE_KEY",     REGIT_USE_KEY);
    3577           19163 :         REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "MATCH",       REGIT_MODE_MATCH);
    3578           19163 :         REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "GET_MATCH",   REGIT_MODE_GET_MATCH);
    3579           19163 :         REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "ALL_MATCHES", REGIT_MODE_ALL_MATCHES);
    3580           19163 :         REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "SPLIT",       REGIT_MODE_SPLIT);
    3581           19163 :         REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "REPLACE",     REGIT_MODE_REPLACE);
    3582           19163 :         REGISTER_SPL_PROPERTY(RegexIterator, "replacement", 0);
    3583           19163 :         REGISTER_SPL_SUB_CLASS_EX(RecursiveRegexIterator, RegexIterator, spl_dual_it_new, spl_funcs_RecursiveRegexIterator);
    3584           19163 :         REGISTER_SPL_IMPLEMENTS(RecursiveRegexIterator, RecursiveIterator);
    3585                 : #else
    3586                 :         spl_ce_RegexIterator = NULL;
    3587                 :         spl_ce_RecursiveRegexIterator = NULL;
    3588                 : #endif
    3589                 : 
    3590           19163 :         REGISTER_SPL_STD_CLASS_EX(EmptyIterator, NULL, spl_funcs_EmptyIterator);
    3591           19163 :         REGISTER_SPL_ITERATOR(EmptyIterator);
    3592                 : 
    3593           19163 :         REGISTER_SPL_SUB_CLASS_EX(RecursiveTreeIterator, RecursiveIteratorIterator, spl_RecursiveTreeIterator_new, spl_funcs_RecursiveTreeIterator);
    3594           19163 :         REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "BYPASS_CURRENT",      RTIT_BYPASS_CURRENT);
    3595           19163 :         REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "BYPASS_KEY",          RTIT_BYPASS_KEY);
    3596           19163 :         REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_LEFT",         0);
    3597           19163 :         REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_MID_HAS_NEXT", 1);
    3598           19163 :         REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_MID_LAST",     2);
    3599           19163 :         REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_END_HAS_NEXT", 3);
    3600           19163 :         REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_END_LAST",     4);
    3601           19163 :         REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_RIGHT",        5);
    3602                 : 
    3603           19163 :         return SUCCESS;
    3604                 : }
    3605                 : /* }}} */
    3606                 : 
    3607                 : /*
    3608                 :  * Local variables:
    3609                 :  * tab-width: 4
    3610                 :  * c-basic-offset: 4
    3611                 :  * End:
    3612                 :  * vim600: fdm=marker
    3613                 :  * vim: noet sw=4 ts=4
    3614                 :  */

Generated by: LCOV version 1.7

Generated at Mon, 14 May 2012 16:50:23 +0000 (42 hours ago)

Copyright © 2005-2012 The PHP Group
All rights reserved.