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