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