You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1140 lines
33 KiB

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