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-21 Instrumented lines: 1383
Code covered: 93.4 % Executed lines: 1292
Legend: not executed executed

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

Generated by: LTP GCOV extension version 1.5

Generated at Sat, 21 Nov 2009 12:27:10 +0000 (3 days ago)

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