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

LTP GCOV extension - code coverage report
Current view: directory - spl - spl_iterators.c
Test: PHP Code Coverage
Date: 2009-11-23 Instrumented lines: 1426
Code covered: 92.3 % Executed lines: 1316
Legend: not executed executed

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

Generated by: LTP GCOV extension version 1.5

Generated at Mon, 23 Nov 2009 17:39:39 +0000 (33 hours ago)

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