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