1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2018 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Author: Antony Dovgal <tony@daylessday.org> |
16 | Etienne Kneuss <colder@php.net> |
17 +----------------------------------------------------------------------+
18 */
19
20 /* $Id$ */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "php.h"
27 #include "php_ini.h"
28 #include "ext/standard/info.h"
29 #include "zend_exceptions.h"
30
31 #include "php_spl.h"
32 #include "spl_functions.h"
33 #include "spl_engine.h"
34 #include "spl_fixedarray.h"
35 #include "spl_exceptions.h"
36 #include "spl_iterators.h"
37
38 zend_object_handlers spl_handler_SplFixedArray;
39 PHPAPI zend_class_entry *spl_ce_SplFixedArray;
40
41 #ifdef COMPILE_DL_SPL_FIXEDARRAY
42 ZEND_GET_MODULE(spl_fixedarray)
43 #endif
44
45 typedef struct _spl_fixedarray { /* {{{ */
46 zend_long size;
47 zval *elements;
48 } spl_fixedarray;
49 /* }}} */
50
51 typedef struct _spl_fixedarray_object { /* {{{ */
52 spl_fixedarray array;
53 zend_function *fptr_offset_get;
54 zend_function *fptr_offset_set;
55 zend_function *fptr_offset_has;
56 zend_function *fptr_offset_del;
57 zend_function *fptr_count;
58 int current;
59 int flags;
60 zend_class_entry *ce_get_iterator;
61 zend_object std;
62 } spl_fixedarray_object;
63 /* }}} */
64
65 typedef struct _spl_fixedarray_it { /* {{{ */
66 zend_user_iterator intern;
67 } spl_fixedarray_it;
68 /* }}} */
69
70 #define SPL_FIXEDARRAY_OVERLOADED_REWIND 0x0001
71 #define SPL_FIXEDARRAY_OVERLOADED_VALID 0x0002
72 #define SPL_FIXEDARRAY_OVERLOADED_KEY 0x0004
73 #define SPL_FIXEDARRAY_OVERLOADED_CURRENT 0x0008
74 #define SPL_FIXEDARRAY_OVERLOADED_NEXT 0x0010
75
spl_fixed_array_from_obj(zend_object * obj)76 static inline spl_fixedarray_object *spl_fixed_array_from_obj(zend_object *obj) /* {{{ */ {
77 return (spl_fixedarray_object*)((char*)(obj) - XtOffsetOf(spl_fixedarray_object, std));
78 }
79 /* }}} */
80
81 #define Z_SPLFIXEDARRAY_P(zv) spl_fixed_array_from_obj(Z_OBJ_P((zv)))
82
spl_fixedarray_init(spl_fixedarray * array,zend_long size)83 static void spl_fixedarray_init(spl_fixedarray *array, zend_long size) /* {{{ */
84 {
85 if (size > 0) {
86 array->size = 0; /* reset size in case ecalloc() fails */
87 array->elements = ecalloc(size, sizeof(zval));
88 array->size = size;
89 } else {
90 array->elements = NULL;
91 array->size = 0;
92 }
93 }
94 /* }}} */
95
spl_fixedarray_resize(spl_fixedarray * array,zend_long size)96 static void spl_fixedarray_resize(spl_fixedarray *array, zend_long size) /* {{{ */
97 {
98 if (size == array->size) {
99 /* nothing to do */
100 return;
101 }
102
103 /* first initialization */
104 if (array->size == 0) {
105 spl_fixedarray_init(array, size);
106 return;
107 }
108
109 /* clearing the array */
110 if (size == 0) {
111 zend_long i;
112
113 for (i = 0; i < array->size; i++) {
114 zval_ptr_dtor(&(array->elements[i]));
115 }
116
117 if (array->elements) {
118 efree(array->elements);
119 array->elements = NULL;
120 }
121 } else if (size > array->size) {
122 array->elements = safe_erealloc(array->elements, size, sizeof(zval), 0);
123 memset(array->elements + array->size, '\0', sizeof(zval) * (size - array->size));
124 } else { /* size < array->size */
125 zend_long i;
126
127 for (i = size; i < array->size; i++) {
128 zval_ptr_dtor(&(array->elements[i]));
129 }
130 array->elements = erealloc(array->elements, sizeof(zval) * size);
131 }
132
133 array->size = size;
134 }
135 /* }}} */
136
spl_fixedarray_copy(spl_fixedarray * to,spl_fixedarray * from)137 static void spl_fixedarray_copy(spl_fixedarray *to, spl_fixedarray *from) /* {{{ */
138 {
139 int i;
140 for (i = 0; i < from->size; i++) {
141 ZVAL_COPY(&to->elements[i], &from->elements[i]);
142 }
143 }
144 /* }}} */
145
spl_fixedarray_object_get_gc(zval * obj,zval ** table,int * n)146 static HashTable* spl_fixedarray_object_get_gc(zval *obj, zval **table, int *n) /* {{{{ */
147 {
148 spl_fixedarray_object *intern = Z_SPLFIXEDARRAY_P(obj);
149 HashTable *ht = zend_std_get_properties(obj);
150
151 *table = intern->array.elements;
152 *n = (int)intern->array.size;
153
154 return ht;
155 }
156 /* }}}} */
157
spl_fixedarray_object_get_properties(zval * obj)158 static HashTable* spl_fixedarray_object_get_properties(zval *obj) /* {{{{ */
159 {
160 spl_fixedarray_object *intern = Z_SPLFIXEDARRAY_P(obj);
161 HashTable *ht = zend_std_get_properties(obj);
162 zend_long i = 0;
163
164 if (intern->array.size > 0) {
165 zend_long j = zend_hash_num_elements(ht);
166
167 for (i = 0; i < intern->array.size; i++) {
168 if (!Z_ISUNDEF(intern->array.elements[i])) {
169 zend_hash_index_update(ht, i, &intern->array.elements[i]);
170 if (Z_REFCOUNTED(intern->array.elements[i])){
171 Z_ADDREF(intern->array.elements[i]);
172 }
173 } else {
174 zend_hash_index_update(ht, i, &EG(uninitialized_zval));
175 }
176 }
177 if (j > intern->array.size) {
178 for (i = intern->array.size; i < j; ++i) {
179 zend_hash_index_del(ht, i);
180 }
181 }
182 }
183
184 return ht;
185 }
186 /* }}}} */
187
spl_fixedarray_object_free_storage(zend_object * object)188 static void spl_fixedarray_object_free_storage(zend_object *object) /* {{{ */
189 {
190 spl_fixedarray_object *intern = spl_fixed_array_from_obj(object);
191 zend_long i;
192
193 if (intern->array.size > 0) {
194 for (i = 0; i < intern->array.size; i++) {
195 zval_ptr_dtor(&(intern->array.elements[i]));
196 }
197
198 if (intern->array.size > 0 && intern->array.elements) {
199 efree(intern->array.elements);
200 }
201 }
202
203 zend_object_std_dtor(&intern->std);
204 }
205 /* }}} */
206
207 zend_object_iterator *spl_fixedarray_get_iterator(zend_class_entry *ce, zval *object, int by_ref);
208
spl_fixedarray_object_new_ex(zend_class_entry * class_type,zval * orig,int clone_orig)209 static zend_object *spl_fixedarray_object_new_ex(zend_class_entry *class_type, zval *orig, int clone_orig) /* {{{ */
210 {
211 spl_fixedarray_object *intern;
212 zend_class_entry *parent = class_type;
213 int inherited = 0;
214
215 intern = ecalloc(1, sizeof(spl_fixedarray_object) + zend_object_properties_size(parent));
216
217 zend_object_std_init(&intern->std, class_type);
218 object_properties_init(&intern->std, class_type);
219
220 intern->current = 0;
221 intern->flags = 0;
222
223 if (orig && clone_orig) {
224 spl_fixedarray_object *other = Z_SPLFIXEDARRAY_P(orig);
225 intern->ce_get_iterator = other->ce_get_iterator;
226 spl_fixedarray_init(&intern->array, other->array.size);
227 spl_fixedarray_copy(&intern->array, &other->array);
228 }
229
230 while (parent) {
231 if (parent == spl_ce_SplFixedArray) {
232 intern->std.handlers = &spl_handler_SplFixedArray;
233 class_type->get_iterator = spl_fixedarray_get_iterator;
234 break;
235 }
236
237 parent = parent->parent;
238 inherited = 1;
239 }
240
241 if (!parent) { /* this must never happen */
242 php_error_docref(NULL, E_COMPILE_ERROR, "Internal compiler error, Class is not child of SplFixedArray");
243 }
244
245 if (!class_type->iterator_funcs.zf_current) {
246 class_type->iterator_funcs.zf_rewind = zend_hash_str_find_ptr(&class_type->function_table, "rewind", sizeof("rewind") - 1);
247 class_type->iterator_funcs.zf_valid = zend_hash_str_find_ptr(&class_type->function_table, "valid", sizeof("valid") - 1);
248 class_type->iterator_funcs.zf_key = zend_hash_str_find_ptr(&class_type->function_table, "key", sizeof("key") - 1);
249 class_type->iterator_funcs.zf_current = zend_hash_str_find_ptr(&class_type->function_table, "current", sizeof("current") - 1);
250 class_type->iterator_funcs.zf_next = zend_hash_str_find_ptr(&class_type->function_table, "next", sizeof("next") - 1);
251 }
252 if (inherited) {
253 if (class_type->iterator_funcs.zf_rewind->common.scope != parent) {
254 intern->flags |= SPL_FIXEDARRAY_OVERLOADED_REWIND;
255 }
256 if (class_type->iterator_funcs.zf_valid->common.scope != parent) {
257 intern->flags |= SPL_FIXEDARRAY_OVERLOADED_VALID;
258 }
259 if (class_type->iterator_funcs.zf_key->common.scope != parent) {
260 intern->flags |= SPL_FIXEDARRAY_OVERLOADED_KEY;
261 }
262 if (class_type->iterator_funcs.zf_current->common.scope != parent) {
263 intern->flags |= SPL_FIXEDARRAY_OVERLOADED_CURRENT;
264 }
265 if (class_type->iterator_funcs.zf_next->common.scope != parent) {
266 intern->flags |= SPL_FIXEDARRAY_OVERLOADED_NEXT;
267 }
268
269 intern->fptr_offset_get = zend_hash_str_find_ptr(&class_type->function_table, "offsetget", sizeof("offsetget") - 1);
270 if (intern->fptr_offset_get->common.scope == parent) {
271 intern->fptr_offset_get = NULL;
272 }
273 intern->fptr_offset_set = zend_hash_str_find_ptr(&class_type->function_table, "offsetset", sizeof("offsetset") - 1);
274 if (intern->fptr_offset_set->common.scope == parent) {
275 intern->fptr_offset_set = NULL;
276 }
277 intern->fptr_offset_has = zend_hash_str_find_ptr(&class_type->function_table, "offsetexists", sizeof("offsetexists") - 1);
278 if (intern->fptr_offset_has->common.scope == parent) {
279 intern->fptr_offset_has = NULL;
280 }
281 intern->fptr_offset_del = zend_hash_str_find_ptr(&class_type->function_table, "offsetunset", sizeof("offsetunset") - 1);
282 if (intern->fptr_offset_del->common.scope == parent) {
283 intern->fptr_offset_del = NULL;
284 }
285 intern->fptr_count = zend_hash_str_find_ptr(&class_type->function_table, "count", sizeof("count") - 1);
286 if (intern->fptr_count->common.scope == parent) {
287 intern->fptr_count = NULL;
288 }
289 }
290
291 return &intern->std;
292 }
293 /* }}} */
294
spl_fixedarray_new(zend_class_entry * class_type)295 static zend_object *spl_fixedarray_new(zend_class_entry *class_type) /* {{{ */
296 {
297 return spl_fixedarray_object_new_ex(class_type, NULL, 0);
298 }
299 /* }}} */
300
spl_fixedarray_object_clone(zval * zobject)301 static zend_object *spl_fixedarray_object_clone(zval *zobject) /* {{{ */
302 {
303 zend_object *old_object;
304 zend_object *new_object;
305
306 old_object = Z_OBJ_P(zobject);
307 new_object = spl_fixedarray_object_new_ex(old_object->ce, zobject, 1);
308
309 zend_objects_clone_members(new_object, old_object);
310
311 return new_object;
312 }
313 /* }}} */
314
spl_fixedarray_object_read_dimension_helper(spl_fixedarray_object * intern,zval * offset)315 static inline zval *spl_fixedarray_object_read_dimension_helper(spl_fixedarray_object *intern, zval *offset) /* {{{ */
316 {
317 zend_long index;
318
319 /* we have to return NULL on error here to avoid memleak because of
320 * ZE duplicating uninitialized_zval_ptr */
321 if (!offset) {
322 zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0);
323 return NULL;
324 }
325
326 if (Z_TYPE_P(offset) != IS_LONG) {
327 index = spl_offset_convert_to_long(offset);
328 } else {
329 index = Z_LVAL_P(offset);
330 }
331
332 if (index < 0 || index >= intern->array.size) {
333 zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0);
334 return NULL;
335 } else if (Z_ISUNDEF(intern->array.elements[index])) {
336 return NULL;
337 } else {
338 return &intern->array.elements[index];
339 }
340 }
341 /* }}} */
342
spl_fixedarray_object_read_dimension(zval * object,zval * offset,int type,zval * rv)343 static zval *spl_fixedarray_object_read_dimension(zval *object, zval *offset, int type, zval *rv) /* {{{ */
344 {
345 spl_fixedarray_object *intern;
346
347 intern = Z_SPLFIXEDARRAY_P(object);
348
349 if (type == BP_VAR_IS && intern->fptr_offset_has) {
350 SEPARATE_ARG_IF_REF(offset);
351 zend_call_method_with_1_params(object, intern->std.ce, &intern->fptr_offset_has, "offsetexists", rv, offset);
352 if (UNEXPECTED(Z_ISUNDEF_P(rv))) {
353 zval_ptr_dtor(offset);
354 return NULL;
355 }
356 if (!i_zend_is_true(rv)) {
357 zval_ptr_dtor(offset);
358 zval_ptr_dtor(rv);
359 return &EG(uninitialized_zval);
360 }
361 zval_ptr_dtor(rv);
362 }
363
364 if (intern->fptr_offset_get) {
365 zval tmp;
366 if (!offset) {
367 ZVAL_NULL(&tmp);
368 offset = &tmp;
369 } else {
370 SEPARATE_ARG_IF_REF(offset);
371 }
372 zend_call_method_with_1_params(object, intern->std.ce, &intern->fptr_offset_get, "offsetGet", rv, offset);
373 zval_ptr_dtor(offset);
374 if (!Z_ISUNDEF_P(rv)) {
375 return rv;
376 }
377 return &EG(uninitialized_zval);
378 }
379
380 return spl_fixedarray_object_read_dimension_helper(intern, offset);
381 }
382 /* }}} */
383
spl_fixedarray_object_write_dimension_helper(spl_fixedarray_object * intern,zval * offset,zval * value)384 static inline void spl_fixedarray_object_write_dimension_helper(spl_fixedarray_object *intern, zval *offset, zval *value) /* {{{ */
385 {
386 zend_long index;
387
388 if (!offset) {
389 /* '$array[] = value' syntax is not supported */
390 zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0);
391 return;
392 }
393
394 if (Z_TYPE_P(offset) != IS_LONG) {
395 index = spl_offset_convert_to_long(offset);
396 } else {
397 index = Z_LVAL_P(offset);
398 }
399
400 if (index < 0 || index >= intern->array.size) {
401 zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0);
402 return;
403 } else {
404 if (!Z_ISUNDEF(intern->array.elements[index])) {
405 zval_ptr_dtor(&(intern->array.elements[index]));
406 }
407 ZVAL_DEREF(value);
408 ZVAL_COPY(&intern->array.elements[index], value);
409 }
410 }
411 /* }}} */
412
spl_fixedarray_object_write_dimension(zval * object,zval * offset,zval * value)413 static void spl_fixedarray_object_write_dimension(zval *object, zval *offset, zval *value) /* {{{ */
414 {
415 spl_fixedarray_object *intern;
416 zval tmp;
417
418 intern = Z_SPLFIXEDARRAY_P(object);
419
420 if (intern->fptr_offset_set) {
421 if (!offset) {
422 ZVAL_NULL(&tmp);
423 offset = &tmp;
424 } else {
425 SEPARATE_ARG_IF_REF(offset);
426 }
427 SEPARATE_ARG_IF_REF(value);
428 zend_call_method_with_2_params(object, intern->std.ce, &intern->fptr_offset_set, "offsetSet", NULL, offset, value);
429 zval_ptr_dtor(value);
430 zval_ptr_dtor(offset);
431 return;
432 }
433
434 spl_fixedarray_object_write_dimension_helper(intern, offset, value);
435 }
436 /* }}} */
437
spl_fixedarray_object_unset_dimension_helper(spl_fixedarray_object * intern,zval * offset)438 static inline void spl_fixedarray_object_unset_dimension_helper(spl_fixedarray_object *intern, zval *offset) /* {{{ */
439 {
440 zend_long index;
441
442 if (Z_TYPE_P(offset) != IS_LONG) {
443 index = spl_offset_convert_to_long(offset);
444 } else {
445 index = Z_LVAL_P(offset);
446 }
447
448 if (index < 0 || index >= intern->array.size) {
449 zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0);
450 return;
451 } else {
452 zval_ptr_dtor(&(intern->array.elements[index]));
453 ZVAL_UNDEF(&intern->array.elements[index]);
454 }
455 }
456 /* }}} */
457
spl_fixedarray_object_unset_dimension(zval * object,zval * offset)458 static void spl_fixedarray_object_unset_dimension(zval *object, zval *offset) /* {{{ */
459 {
460 spl_fixedarray_object *intern;
461
462 intern = Z_SPLFIXEDARRAY_P(object);
463
464 if (intern->fptr_offset_del) {
465 SEPARATE_ARG_IF_REF(offset);
466 zend_call_method_with_1_params(object, intern->std.ce, &intern->fptr_offset_del, "offsetUnset", NULL, offset);
467 zval_ptr_dtor(offset);
468 return;
469 }
470
471 spl_fixedarray_object_unset_dimension_helper(intern, offset);
472
473 }
474 /* }}} */
475
spl_fixedarray_object_has_dimension_helper(spl_fixedarray_object * intern,zval * offset,int check_empty)476 static inline int spl_fixedarray_object_has_dimension_helper(spl_fixedarray_object *intern, zval *offset, int check_empty) /* {{{ */
477 {
478 zend_long index;
479 int retval;
480
481 if (Z_TYPE_P(offset) != IS_LONG) {
482 index = spl_offset_convert_to_long(offset);
483 } else {
484 index = Z_LVAL_P(offset);
485 }
486
487 if (index < 0 || index >= intern->array.size) {
488 retval = 0;
489 } else {
490 if (Z_ISUNDEF(intern->array.elements[index])) {
491 retval = 0;
492 } else if (check_empty) {
493 if (zend_is_true(&intern->array.elements[index])) {
494 retval = 1;
495 } else {
496 retval = 0;
497 }
498 } else { /* != NULL and !check_empty */
499 retval = 1;
500 }
501 }
502
503 return retval;
504 }
505 /* }}} */
506
spl_fixedarray_object_has_dimension(zval * object,zval * offset,int check_empty)507 static int spl_fixedarray_object_has_dimension(zval *object, zval *offset, int check_empty) /* {{{ */
508 {
509 spl_fixedarray_object *intern;
510
511 intern = Z_SPLFIXEDARRAY_P(object);
512
513 if (intern->fptr_offset_has) {
514 zval rv;
515 SEPARATE_ARG_IF_REF(offset);
516 zend_call_method_with_1_params(object, intern->std.ce, &intern->fptr_offset_has, "offsetExists", &rv, offset);
517 zval_ptr_dtor(offset);
518 if (!Z_ISUNDEF(rv)) {
519 zend_bool result = zend_is_true(&rv);
520 zval_ptr_dtor(&rv);
521 return result;
522 }
523 return 0;
524 }
525
526 return spl_fixedarray_object_has_dimension_helper(intern, offset, check_empty);
527 }
528 /* }}} */
529
spl_fixedarray_object_count_elements(zval * object,zend_long * count)530 static int spl_fixedarray_object_count_elements(zval *object, zend_long *count) /* {{{ */
531 {
532 spl_fixedarray_object *intern;
533
534 intern = Z_SPLFIXEDARRAY_P(object);
535 if (intern->fptr_count) {
536 zval rv;
537 zend_call_method_with_0_params(object, intern->std.ce, &intern->fptr_count, "count", &rv);
538 if (!Z_ISUNDEF(rv)) {
539 *count = zval_get_long(&rv);
540 zval_ptr_dtor(&rv);
541 } else {
542 *count = 0;
543 }
544 } else {
545 *count = intern->array.size;
546 }
547 return SUCCESS;
548 }
549 /* }}} */
550
551 /* {{{ proto void SplFixedArray::__construct([int size])
552 */
SPL_METHOD(SplFixedArray,__construct)553 SPL_METHOD(SplFixedArray, __construct)
554 {
555 zval *object = getThis();
556 spl_fixedarray_object *intern;
557 zend_long size = 0;
558
559 if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "|l", &size) == FAILURE) {
560 return;
561 }
562
563 if (size < 0) {
564 zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "array size cannot be less than zero");
565 return;
566 }
567
568 intern = Z_SPLFIXEDARRAY_P(object);
569
570 if (intern->array.size > 0) {
571 /* called __construct() twice, bail out */
572 return;
573 }
574
575 spl_fixedarray_init(&intern->array, size);
576 }
577 /* }}} */
578
579 /* {{{ proto void SplFixedArray::__wakeup()
580 */
SPL_METHOD(SplFixedArray,__wakeup)581 SPL_METHOD(SplFixedArray, __wakeup)
582 {
583 spl_fixedarray_object *intern = Z_SPLFIXEDARRAY_P(getThis());
584 HashTable *intern_ht = zend_std_get_properties(getThis());
585 zval *data;
586
587 if (zend_parse_parameters_none() == FAILURE) {
588 return;
589 }
590
591 if (intern->array.size == 0) {
592 int index = 0;
593 int size = zend_hash_num_elements(intern_ht);
594
595 spl_fixedarray_init(&intern->array, size);
596
597 ZEND_HASH_FOREACH_VAL(intern_ht, data) {
598 if (Z_REFCOUNTED_P(data)) {
599 Z_ADDREF_P(data);
600 }
601 ZVAL_COPY_VALUE(&intern->array.elements[index], data);
602 index++;
603 } ZEND_HASH_FOREACH_END();
604
605 /* Remove the unserialised properties, since we now have the elements
606 * within the spl_fixedarray_object structure. */
607 zend_hash_clean(intern_ht);
608 }
609 }
610 /* }}} */
611
612 /* {{{ proto int SplFixedArray::count(void)
613 */
SPL_METHOD(SplFixedArray,count)614 SPL_METHOD(SplFixedArray, count)
615 {
616 zval *object = getThis();
617 spl_fixedarray_object *intern;
618
619 if (zend_parse_parameters_none() == FAILURE) {
620 return;
621 }
622
623 intern = Z_SPLFIXEDARRAY_P(object);
624 RETURN_LONG(intern->array.size);
625 }
626 /* }}} */
627
628 /* {{{ proto object SplFixedArray::toArray()
629 */
SPL_METHOD(SplFixedArray,toArray)630 SPL_METHOD(SplFixedArray, toArray)
631 {
632 spl_fixedarray_object *intern;
633
634 if (zend_parse_parameters_none() == FAILURE) {
635 return;
636 }
637
638 intern = Z_SPLFIXEDARRAY_P(getThis());
639
640 array_init(return_value);
641 if (intern->array.size > 0) {
642 int i = 0;
643 for (; i < intern->array.size; i++) {
644 if (!Z_ISUNDEF(intern->array.elements[i])) {
645 zend_hash_index_update(Z_ARRVAL_P(return_value), i, &intern->array.elements[i]);
646 if (Z_REFCOUNTED(intern->array.elements[i])) {
647 Z_ADDREF(intern->array.elements[i]);
648 }
649 } else {
650 zend_hash_index_update(Z_ARRVAL_P(return_value), i, &EG(uninitialized_zval));
651 }
652 }
653 }
654 }
655 /* }}} */
656
657 /* {{{ proto object SplFixedArray::fromArray(array data[, bool save_indexes])
658 */
SPL_METHOD(SplFixedArray,fromArray)659 SPL_METHOD(SplFixedArray, fromArray)
660 {
661 zval *data;
662 spl_fixedarray array;
663 spl_fixedarray_object *intern;
664 int num;
665 zend_bool save_indexes = 1;
666
667 if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|b", &data, &save_indexes) == FAILURE) {
668 return;
669 }
670
671 num = zend_hash_num_elements(Z_ARRVAL_P(data));
672
673 if (num > 0 && save_indexes) {
674 zval *element;
675 zend_string *str_index;
676 zend_ulong num_index, max_index = 0;
677 zend_long tmp;
678
679 ZEND_HASH_FOREACH_KEY(Z_ARRVAL_P(data), num_index, str_index) {
680 if (str_index != NULL || (zend_long)num_index < 0) {
681 zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "array must contain only positive integer keys");
682 return;
683 }
684
685 if (num_index > max_index) {
686 max_index = num_index;
687 }
688 } ZEND_HASH_FOREACH_END();
689
690 tmp = max_index + 1;
691 if (tmp <= 0) {
692 zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "integer overflow detected");
693 return;
694 }
695 spl_fixedarray_init(&array, tmp);
696
697 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(data), num_index, str_index, element) {
698 ZVAL_DEREF(element);
699 ZVAL_COPY(&array.elements[num_index], element);
700 } ZEND_HASH_FOREACH_END();
701
702 } else if (num > 0 && !save_indexes) {
703 zval *element;
704 zend_long i = 0;
705
706 spl_fixedarray_init(&array, num);
707
708 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(data), element) {
709 ZVAL_DEREF(element);
710 ZVAL_COPY(&array.elements[i], element);
711 i++;
712 } ZEND_HASH_FOREACH_END();
713 } else {
714 spl_fixedarray_init(&array, 0);
715 }
716
717 object_init_ex(return_value, spl_ce_SplFixedArray);
718
719 intern = Z_SPLFIXEDARRAY_P(return_value);
720 intern->array = array;
721 }
722 /* }}} */
723
724 /* {{{ proto int SplFixedArray::getSize(void)
725 */
SPL_METHOD(SplFixedArray,getSize)726 SPL_METHOD(SplFixedArray, getSize)
727 {
728 zval *object = getThis();
729 spl_fixedarray_object *intern;
730
731 if (zend_parse_parameters_none() == FAILURE) {
732 return;
733 }
734
735 intern = Z_SPLFIXEDARRAY_P(object);
736 RETURN_LONG(intern->array.size);
737 }
738 /* }}} */
739
740 /* {{{ proto bool SplFixedArray::setSize(int size)
741 */
SPL_METHOD(SplFixedArray,setSize)742 SPL_METHOD(SplFixedArray, setSize)
743 {
744 zval *object = getThis();
745 spl_fixedarray_object *intern;
746 zend_long size;
747
748 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &size) == FAILURE) {
749 return;
750 }
751
752 if (size < 0) {
753 zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "array size cannot be less than zero");
754 return;
755 }
756
757 intern = Z_SPLFIXEDARRAY_P(object);
758
759 spl_fixedarray_resize(&intern->array, size);
760 RETURN_TRUE;
761 }
762 /* }}} */
763
764 /* {{{ proto bool SplFixedArray::offsetExists(mixed $index)
765 Returns whether the requested $index exists. */
SPL_METHOD(SplFixedArray,offsetExists)766 SPL_METHOD(SplFixedArray, offsetExists)
767 {
768 zval *zindex;
769 spl_fixedarray_object *intern;
770
771 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zindex) == FAILURE) {
772 return;
773 }
774
775 intern = Z_SPLFIXEDARRAY_P(getThis());
776
777 RETURN_BOOL(spl_fixedarray_object_has_dimension_helper(intern, zindex, 0));
778 } /* }}} */
779
780 /* {{{ proto mixed SplFixedArray::offsetGet(mixed $index)
781 Returns the value at the specified $index. */
SPL_METHOD(SplFixedArray,offsetGet)782 SPL_METHOD(SplFixedArray, offsetGet)
783 {
784 zval *zindex, *value;
785 spl_fixedarray_object *intern;
786
787 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zindex) == FAILURE) {
788 return;
789 }
790
791 intern = Z_SPLFIXEDARRAY_P(getThis());
792 value = spl_fixedarray_object_read_dimension_helper(intern, zindex);
793
794 if (value) {
795 ZVAL_DEREF(value);
796 ZVAL_COPY(return_value, value);
797 } else {
798 RETURN_NULL();
799 }
800 } /* }}} */
801
802 /* {{{ proto void SplFixedArray::offsetSet(mixed $index, mixed $newval)
803 Sets the value at the specified $index to $newval. */
SPL_METHOD(SplFixedArray,offsetSet)804 SPL_METHOD(SplFixedArray, offsetSet)
805 {
806 zval *zindex, *value;
807 spl_fixedarray_object *intern;
808
809 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &zindex, &value) == FAILURE) {
810 return;
811 }
812
813 intern = Z_SPLFIXEDARRAY_P(getThis());
814 spl_fixedarray_object_write_dimension_helper(intern, zindex, value);
815
816 } /* }}} */
817
818 /* {{{ proto void SplFixedArray::offsetUnset(mixed $index)
819 Unsets the value at the specified $index. */
SPL_METHOD(SplFixedArray,offsetUnset)820 SPL_METHOD(SplFixedArray, offsetUnset)
821 {
822 zval *zindex;
823 spl_fixedarray_object *intern;
824
825 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zindex) == FAILURE) {
826 return;
827 }
828
829 intern = Z_SPLFIXEDARRAY_P(getThis());
830 spl_fixedarray_object_unset_dimension_helper(intern, zindex);
831
832 } /* }}} */
833
spl_fixedarray_it_dtor(zend_object_iterator * iter)834 static void spl_fixedarray_it_dtor(zend_object_iterator *iter) /* {{{ */
835 {
836 spl_fixedarray_it *iterator = (spl_fixedarray_it *)iter;
837
838 zend_user_it_invalidate_current(iter);
839 zval_ptr_dtor(&iterator->intern.it.data);
840 }
841 /* }}} */
842
spl_fixedarray_it_rewind(zend_object_iterator * iter)843 static void spl_fixedarray_it_rewind(zend_object_iterator *iter) /* {{{ */
844 {
845 spl_fixedarray_object *object = Z_SPLFIXEDARRAY_P(&iter->data);
846
847 if (object->flags & SPL_FIXEDARRAY_OVERLOADED_REWIND) {
848 zend_user_it_rewind(iter);
849 } else {
850 object->current = 0;
851 }
852 }
853 /* }}} */
854
spl_fixedarray_it_valid(zend_object_iterator * iter)855 static int spl_fixedarray_it_valid(zend_object_iterator *iter) /* {{{ */
856 {
857 spl_fixedarray_object *object = Z_SPLFIXEDARRAY_P(&iter->data);
858
859 if (object->flags & SPL_FIXEDARRAY_OVERLOADED_VALID) {
860 return zend_user_it_valid(iter);
861 }
862
863 if (object->current >= 0 && object->current < object->array.size) {
864 return SUCCESS;
865 }
866
867 return FAILURE;
868 }
869 /* }}} */
870
spl_fixedarray_it_get_current_data(zend_object_iterator * iter)871 static zval *spl_fixedarray_it_get_current_data(zend_object_iterator *iter) /* {{{ */
872 {
873 zval zindex;
874 spl_fixedarray_object *object = Z_SPLFIXEDARRAY_P(&iter->data);
875
876 if (object->flags & SPL_FIXEDARRAY_OVERLOADED_CURRENT) {
877 return zend_user_it_get_current_data(iter);
878 } else {
879 zval *data;
880
881 ZVAL_LONG(&zindex, object->current);
882
883 data = spl_fixedarray_object_read_dimension_helper(object, &zindex);
884 zval_ptr_dtor(&zindex);
885
886 if (data == NULL) {
887 data = &EG(uninitialized_zval);
888 }
889 return data;
890 }
891 }
892 /* }}} */
893
spl_fixedarray_it_get_current_key(zend_object_iterator * iter,zval * key)894 static void spl_fixedarray_it_get_current_key(zend_object_iterator *iter, zval *key) /* {{{ */
895 {
896 spl_fixedarray_object *object = Z_SPLFIXEDARRAY_P(&iter->data);
897
898 if (object->flags & SPL_FIXEDARRAY_OVERLOADED_KEY) {
899 zend_user_it_get_current_key(iter, key);
900 } else {
901 ZVAL_LONG(key, object->current);
902 }
903 }
904 /* }}} */
905
spl_fixedarray_it_move_forward(zend_object_iterator * iter)906 static void spl_fixedarray_it_move_forward(zend_object_iterator *iter) /* {{{ */
907 {
908 spl_fixedarray_object *object = Z_SPLFIXEDARRAY_P(&iter->data);
909
910 if (object->flags & SPL_FIXEDARRAY_OVERLOADED_NEXT) {
911 zend_user_it_move_forward(iter);
912 } else {
913 zend_user_it_invalidate_current(iter);
914 object->current++;
915 }
916 }
917 /* }}} */
918
919 /* {{{ proto int SplFixedArray::key()
920 Return current array key */
SPL_METHOD(SplFixedArray,key)921 SPL_METHOD(SplFixedArray, key)
922 {
923 spl_fixedarray_object *intern = Z_SPLFIXEDARRAY_P(getThis());
924
925 if (zend_parse_parameters_none() == FAILURE) {
926 return;
927 }
928
929 RETURN_LONG(intern->current);
930 }
931 /* }}} */
932
933 /* {{{ proto void SplFixedArray::next()
934 Move to next entry */
SPL_METHOD(SplFixedArray,next)935 SPL_METHOD(SplFixedArray, next)
936 {
937 spl_fixedarray_object *intern = Z_SPLFIXEDARRAY_P(getThis());
938
939 if (zend_parse_parameters_none() == FAILURE) {
940 return;
941 }
942
943 intern->current++;
944 }
945 /* }}} */
946
947 /* {{{ proto bool SplFixedArray::valid()
948 Check whether the datastructure contains more entries */
SPL_METHOD(SplFixedArray,valid)949 SPL_METHOD(SplFixedArray, valid)
950 {
951 spl_fixedarray_object *intern = Z_SPLFIXEDARRAY_P(getThis());
952
953 if (zend_parse_parameters_none() == FAILURE) {
954 return;
955 }
956
957 RETURN_BOOL(intern->current >= 0 && intern->current < intern->array.size);
958 }
959 /* }}} */
960
961 /* {{{ proto void SplFixedArray::rewind()
962 Rewind the datastructure back to the start */
SPL_METHOD(SplFixedArray,rewind)963 SPL_METHOD(SplFixedArray, rewind)
964 {
965 spl_fixedarray_object *intern = Z_SPLFIXEDARRAY_P(getThis());
966
967 if (zend_parse_parameters_none() == FAILURE) {
968 return;
969 }
970
971 intern->current = 0;
972 }
973 /* }}} */
974
975 /* {{{ proto mixed|NULL SplFixedArray::current()
976 Return current datastructure entry */
SPL_METHOD(SplFixedArray,current)977 SPL_METHOD(SplFixedArray, current)
978 {
979 zval zindex, *value;
980 spl_fixedarray_object *intern = Z_SPLFIXEDARRAY_P(getThis());
981
982 if (zend_parse_parameters_none() == FAILURE) {
983 return;
984 }
985
986 ZVAL_LONG(&zindex, intern->current);
987
988 value = spl_fixedarray_object_read_dimension_helper(intern, &zindex);
989
990 zval_ptr_dtor(&zindex);
991
992 if (value) {
993 ZVAL_DEREF(value);
994 ZVAL_COPY(return_value, value);
995 } else {
996 RETURN_NULL();
997 }
998 }
999 /* }}} */
1000
1001 /* iterator handler table */
1002 zend_object_iterator_funcs spl_fixedarray_it_funcs = {
1003 spl_fixedarray_it_dtor,
1004 spl_fixedarray_it_valid,
1005 spl_fixedarray_it_get_current_data,
1006 spl_fixedarray_it_get_current_key,
1007 spl_fixedarray_it_move_forward,
1008 spl_fixedarray_it_rewind,
1009 NULL
1010 };
1011
spl_fixedarray_get_iterator(zend_class_entry * ce,zval * object,int by_ref)1012 zend_object_iterator *spl_fixedarray_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */
1013 {
1014 spl_fixedarray_it *iterator;
1015
1016 if (by_ref) {
1017 zend_throw_exception(spl_ce_RuntimeException, "An iterator cannot be used with foreach by reference", 0);
1018 return NULL;
1019 }
1020
1021 iterator = emalloc(sizeof(spl_fixedarray_it));
1022
1023 zend_iterator_init((zend_object_iterator*)iterator);
1024
1025 ZVAL_COPY(&iterator->intern.it.data, object);
1026 iterator->intern.it.funcs = &spl_fixedarray_it_funcs;
1027 iterator->intern.ce = ce;
1028 ZVAL_UNDEF(&iterator->intern.value);
1029
1030 return &iterator->intern.it;
1031 }
1032 /* }}} */
1033
1034 ZEND_BEGIN_ARG_INFO_EX(arginfo_splfixedarray_construct, 0, 0, 0)
1035 ZEND_ARG_INFO(0, size)
1036 ZEND_END_ARG_INFO()
1037
1038 ZEND_BEGIN_ARG_INFO_EX(arginfo_fixedarray_offsetGet, 0, 0, 1)
1039 ZEND_ARG_INFO(0, index)
1040 ZEND_END_ARG_INFO()
1041
1042 ZEND_BEGIN_ARG_INFO_EX(arginfo_fixedarray_offsetSet, 0, 0, 2)
1043 ZEND_ARG_INFO(0, index)
1044 ZEND_ARG_INFO(0, newval)
1045 ZEND_END_ARG_INFO()
1046
1047 ZEND_BEGIN_ARG_INFO(arginfo_fixedarray_setSize, 0)
1048 ZEND_ARG_INFO(0, value)
1049 ZEND_END_ARG_INFO()
1050
1051 ZEND_BEGIN_ARG_INFO_EX(arginfo_fixedarray_fromArray, 0, 0, 1)
1052 ZEND_ARG_INFO(0, data)
1053 ZEND_ARG_INFO(0, save_indexes)
1054 ZEND_END_ARG_INFO()
1055
1056 ZEND_BEGIN_ARG_INFO(arginfo_splfixedarray_void, 0)
1057 ZEND_END_ARG_INFO()
1058
1059 static zend_function_entry spl_funcs_SplFixedArray[] = { /* {{{ */
1060 SPL_ME(SplFixedArray, __construct, arginfo_splfixedarray_construct,ZEND_ACC_PUBLIC)
1061 SPL_ME(SplFixedArray, __wakeup, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
1062 SPL_ME(SplFixedArray, count, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
1063 SPL_ME(SplFixedArray, toArray, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
1064 SPL_ME(SplFixedArray, fromArray, arginfo_fixedarray_fromArray, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
1065 SPL_ME(SplFixedArray, getSize, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
1066 SPL_ME(SplFixedArray, setSize, arginfo_fixedarray_setSize, ZEND_ACC_PUBLIC)
1067 SPL_ME(SplFixedArray, offsetExists, arginfo_fixedarray_offsetGet, ZEND_ACC_PUBLIC)
1068 SPL_ME(SplFixedArray, offsetGet, arginfo_fixedarray_offsetGet, ZEND_ACC_PUBLIC)
1069 SPL_ME(SplFixedArray, offsetSet, arginfo_fixedarray_offsetSet, ZEND_ACC_PUBLIC)
1070 SPL_ME(SplFixedArray, offsetUnset, arginfo_fixedarray_offsetGet, ZEND_ACC_PUBLIC)
1071 SPL_ME(SplFixedArray, rewind, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
1072 SPL_ME(SplFixedArray, current, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
1073 SPL_ME(SplFixedArray, key, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
1074 SPL_ME(SplFixedArray, next, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
1075 SPL_ME(SplFixedArray, valid, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
1076 PHP_FE_END
1077 };
1078 /* }}} */
1079
1080 /* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(spl_fixedarray)1081 PHP_MINIT_FUNCTION(spl_fixedarray)
1082 {
1083 REGISTER_SPL_STD_CLASS_EX(SplFixedArray, spl_fixedarray_new, spl_funcs_SplFixedArray);
1084 memcpy(&spl_handler_SplFixedArray, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1085
1086 spl_handler_SplFixedArray.offset = XtOffsetOf(spl_fixedarray_object, std);
1087 spl_handler_SplFixedArray.clone_obj = spl_fixedarray_object_clone;
1088 spl_handler_SplFixedArray.read_dimension = spl_fixedarray_object_read_dimension;
1089 spl_handler_SplFixedArray.write_dimension = spl_fixedarray_object_write_dimension;
1090 spl_handler_SplFixedArray.unset_dimension = spl_fixedarray_object_unset_dimension;
1091 spl_handler_SplFixedArray.has_dimension = spl_fixedarray_object_has_dimension;
1092 spl_handler_SplFixedArray.count_elements = spl_fixedarray_object_count_elements;
1093 spl_handler_SplFixedArray.get_properties = spl_fixedarray_object_get_properties;
1094 spl_handler_SplFixedArray.get_gc = spl_fixedarray_object_get_gc;
1095 spl_handler_SplFixedArray.dtor_obj = zend_objects_destroy_object;
1096 spl_handler_SplFixedArray.free_obj = spl_fixedarray_object_free_storage;
1097
1098 REGISTER_SPL_IMPLEMENTS(SplFixedArray, Iterator);
1099 REGISTER_SPL_IMPLEMENTS(SplFixedArray, ArrayAccess);
1100 REGISTER_SPL_IMPLEMENTS(SplFixedArray, Countable);
1101
1102 spl_ce_SplFixedArray->get_iterator = spl_fixedarray_get_iterator;
1103
1104 return SUCCESS;
1105 }
1106 /* }}} */
1107
1108
1109 /*
1110 * Local variables:
1111 * tab-width: 4
1112 * c-basic-offset: 4
1113 * End:
1114 * vim600: noet sw=4 ts=4 fdm=marker
1115 * vim<600: noet sw=4 ts=4
1116 */
1117