spl_fixedarray.c 30 KB

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