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