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