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