common_enum.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. /*
  2. +----------------------------------------------------------------------+
  3. | This source file is subject to version 3.01 of the PHP license, |
  4. | that is bundled with this package in the file LICENSE, and is |
  5. | available through the world-wide-web at the following url: |
  6. | https://www.php.net/license/3_01.txt |
  7. | If you did not receive a copy of the PHP license and are unable to |
  8. | obtain it through the world-wide-web, please send a note to |
  9. | license@php.net so we can mail you a copy immediately. |
  10. +----------------------------------------------------------------------+
  11. | Authors: Gustavo Lopes <cataphract@php.net> |
  12. +----------------------------------------------------------------------+
  13. */
  14. #ifdef HAVE_CONFIG_H
  15. #include "config.h"
  16. #endif
  17. #include "../intl_cppshims.h"
  18. // Fix build on Windows/old versions of ICU
  19. #include <stdio.h>
  20. #include "common_enum.h"
  21. #include "common_arginfo.h"
  22. extern "C" {
  23. #include <zend_interfaces.h>
  24. #include <zend_exceptions.h>
  25. }
  26. zend_class_entry *IntlIterator_ce_ptr;
  27. zend_object_handlers IntlIterator_handlers;
  28. void zoi_with_current_dtor(zend_object_iterator *iter)
  29. {
  30. zoi_with_current *zoiwc = (zoi_with_current*)iter;
  31. if (!Z_ISUNDEF(zoiwc->wrapping_obj)) {
  32. /* we have to copy the pointer because zoiwc->wrapping_obj may be
  33. * changed midway the execution of zval_ptr_dtor() */
  34. zval *zwo = &zoiwc->wrapping_obj;
  35. /* object is still here, we can rely on it to call this again and
  36. * destroy this object */
  37. zval_ptr_dtor(zwo);
  38. } else {
  39. /* Object not here anymore (we've been called by the object free handler)
  40. * Note that the iterator wrapper objects (that also depend on this
  41. * structure) call this function earlier, in the destruction phase, which
  42. * precedes the object free phase. Therefore there's no risk on this
  43. * function being called by the iterator wrapper destructor function and
  44. * not finding the memory of this iterator allocated anymore. */
  45. iter->funcs->invalidate_current(iter);
  46. zoiwc->destroy_it(iter);
  47. }
  48. }
  49. U_CFUNC int zoi_with_current_valid(zend_object_iterator *iter)
  50. {
  51. return Z_ISUNDEF(((zoi_with_current*)iter)->current)? FAILURE : SUCCESS;
  52. }
  53. U_CFUNC zval *zoi_with_current_get_current_data(zend_object_iterator *iter)
  54. {
  55. return &((zoi_with_current*)iter)->current;
  56. }
  57. U_CFUNC void zoi_with_current_invalidate_current(zend_object_iterator *iter)
  58. {
  59. zoi_with_current *zoi_iter = (zoi_with_current*)iter;
  60. if (!Z_ISUNDEF(zoi_iter->current)) {
  61. zval_ptr_dtor(&zoi_iter->current);
  62. ZVAL_UNDEF(&zoi_iter->current); //valid would return FAILURE now
  63. }
  64. }
  65. static void string_enum_current_move_forward(zend_object_iterator *iter)
  66. {
  67. zoi_with_current *zoi_iter = (zoi_with_current*)iter;
  68. INTLITERATOR_METHOD_INIT_VARS;
  69. iter->funcs->invalidate_current(iter);
  70. object = &zoi_iter->wrapping_obj;
  71. INTLITERATOR_METHOD_FETCH_OBJECT_NO_CHECK;
  72. int32_t result_length;
  73. const char *result = ((StringEnumeration*)Z_PTR(iter->data))->next(
  74. &result_length, INTLITERATOR_ERROR_CODE(ii));
  75. intl_error_set_code(NULL, INTLITERATOR_ERROR_CODE(ii));
  76. if (U_FAILURE(INTLITERATOR_ERROR_CODE(ii))) {
  77. intl_errors_set_custom_msg(INTL_DATA_ERROR_P(ii),
  78. "Error fetching next iteration element", 0);
  79. } else if (result) {
  80. ZVAL_STRINGL(&zoi_iter->current, result, result_length);
  81. } //else we've reached the end of the enum, nothing more is required
  82. }
  83. static void string_enum_rewind(zend_object_iterator *iter)
  84. {
  85. zoi_with_current *zoi_iter = (zoi_with_current*)iter;
  86. INTLITERATOR_METHOD_INIT_VARS;
  87. if (!Z_ISUNDEF(zoi_iter->current)) {
  88. iter->funcs->invalidate_current(iter);
  89. }
  90. object = &zoi_iter->wrapping_obj;
  91. INTLITERATOR_METHOD_FETCH_OBJECT_NO_CHECK;
  92. ((StringEnumeration*)Z_PTR(iter->data))->reset(INTLITERATOR_ERROR_CODE(ii));
  93. intl_error_set_code(NULL, INTLITERATOR_ERROR_CODE(ii));
  94. if (U_FAILURE(INTLITERATOR_ERROR_CODE(ii))) {
  95. intl_errors_set_custom_msg(INTL_DATA_ERROR_P(ii),
  96. "Error resetting enumeration", 0);
  97. } else {
  98. iter->funcs->move_forward(iter);
  99. }
  100. }
  101. static void string_enum_destroy_it(zend_object_iterator *iter)
  102. {
  103. delete (StringEnumeration*)Z_PTR(iter->data);
  104. }
  105. static const zend_object_iterator_funcs string_enum_object_iterator_funcs = {
  106. zoi_with_current_dtor,
  107. zoi_with_current_valid,
  108. zoi_with_current_get_current_data,
  109. NULL,
  110. string_enum_current_move_forward,
  111. string_enum_rewind,
  112. zoi_with_current_invalidate_current,
  113. NULL, /* get_gc */
  114. };
  115. U_CFUNC void IntlIterator_from_StringEnumeration(StringEnumeration *se, zval *object)
  116. {
  117. IntlIterator_object *ii;
  118. object_init_ex(object, IntlIterator_ce_ptr);
  119. ii = Z_INTL_ITERATOR_P(object);
  120. ii->iterator = (zend_object_iterator*)emalloc(sizeof(zoi_with_current));
  121. zend_iterator_init(ii->iterator);
  122. ZVAL_PTR(&ii->iterator->data, se);
  123. ii->iterator->funcs = &string_enum_object_iterator_funcs;
  124. ii->iterator->index = 0;
  125. ((zoi_with_current*)ii->iterator)->destroy_it = string_enum_destroy_it;
  126. ZVAL_OBJ(&((zoi_with_current*)ii->iterator)->wrapping_obj, Z_OBJ_P(object));
  127. ZVAL_UNDEF(&((zoi_with_current*)ii->iterator)->current);
  128. }
  129. static void IntlIterator_objects_free(zend_object *object)
  130. {
  131. IntlIterator_object *ii = php_intl_iterator_fetch_object(object);
  132. if (ii->iterator) {
  133. zval *wrapping_objp = &((zoi_with_current*)ii->iterator)->wrapping_obj;
  134. ZVAL_UNDEF(wrapping_objp);
  135. zend_iterator_dtor(ii->iterator);
  136. }
  137. intl_error_reset(INTLITERATOR_ERROR_P(ii));
  138. zend_object_std_dtor(&ii->zo);
  139. }
  140. static zend_object_iterator *IntlIterator_get_iterator(
  141. zend_class_entry *ce, zval *object, int by_ref)
  142. {
  143. if (by_ref) {
  144. zend_throw_exception(NULL,
  145. "Iteration by reference is not supported", 0);
  146. return NULL;
  147. }
  148. IntlIterator_object *ii = Z_INTL_ITERATOR_P(object);
  149. if (ii->iterator == NULL) {
  150. zend_throw_exception(NULL,
  151. "The IntlIterator is not properly constructed", 0);
  152. return NULL;
  153. }
  154. GC_ADDREF(&ii->iterator->std);
  155. return ii->iterator;
  156. }
  157. static zend_object *IntlIterator_object_create(zend_class_entry *ce)
  158. {
  159. IntlIterator_object *intern;
  160. intern = (IntlIterator_object*)ecalloc(1, sizeof(IntlIterator_object) + sizeof(zval) * (ce->default_properties_count - 1));
  161. zend_object_std_init(&intern->zo, ce);
  162. object_properties_init(&intern->zo, ce);
  163. intl_error_init(INTLITERATOR_ERROR_P(intern));
  164. intern->iterator = NULL;
  165. intern->zo.handlers = &IntlIterator_handlers;
  166. return &intern->zo;
  167. }
  168. PHP_METHOD(IntlIterator, current)
  169. {
  170. zval *data;
  171. INTLITERATOR_METHOD_INIT_VARS;
  172. if (zend_parse_parameters_none() == FAILURE) {
  173. RETURN_THROWS();
  174. }
  175. INTLITERATOR_METHOD_FETCH_OBJECT;
  176. data = ii->iterator->funcs->get_current_data(ii->iterator);
  177. if (data) {
  178. RETURN_COPY_DEREF(data);
  179. }
  180. }
  181. PHP_METHOD(IntlIterator, key)
  182. {
  183. INTLITERATOR_METHOD_INIT_VARS;
  184. if (zend_parse_parameters_none() == FAILURE) {
  185. RETURN_THROWS();
  186. }
  187. INTLITERATOR_METHOD_FETCH_OBJECT;
  188. if (ii->iterator->funcs->get_current_key) {
  189. ii->iterator->funcs->get_current_key(ii->iterator, return_value);
  190. } else {
  191. RETURN_LONG(ii->iterator->index);
  192. }
  193. }
  194. PHP_METHOD(IntlIterator, next)
  195. {
  196. INTLITERATOR_METHOD_INIT_VARS;
  197. if (zend_parse_parameters_none() == FAILURE) {
  198. RETURN_THROWS();
  199. }
  200. INTLITERATOR_METHOD_FETCH_OBJECT;
  201. ii->iterator->funcs->move_forward(ii->iterator);
  202. /* foreach also advances the index after the last iteration,
  203. * so I see no problem in incrementing the index here unconditionally */
  204. ii->iterator->index++;
  205. }
  206. PHP_METHOD(IntlIterator, rewind)
  207. {
  208. INTLITERATOR_METHOD_INIT_VARS;
  209. if (zend_parse_parameters_none() == FAILURE) {
  210. RETURN_THROWS();
  211. }
  212. INTLITERATOR_METHOD_FETCH_OBJECT;
  213. if (ii->iterator->funcs->rewind) {
  214. ii->iterator->funcs->rewind(ii->iterator);
  215. } else {
  216. intl_errors_set(INTLITERATOR_ERROR_P(ii), U_UNSUPPORTED_ERROR,
  217. "IntlIterator::rewind: rewind not supported", 0);
  218. }
  219. }
  220. PHP_METHOD(IntlIterator, valid)
  221. {
  222. INTLITERATOR_METHOD_INIT_VARS;
  223. if (zend_parse_parameters_none() == FAILURE) {
  224. RETURN_THROWS();
  225. }
  226. INTLITERATOR_METHOD_FETCH_OBJECT;
  227. RETURN_BOOL(ii->iterator->funcs->valid(ii->iterator) == SUCCESS);
  228. }
  229. /* {{{ intl_register_IntlIterator_class
  230. * Initialize 'IntlIterator' class
  231. */
  232. U_CFUNC void intl_register_IntlIterator_class(void)
  233. {
  234. /* Create and register 'IntlIterator' class. */
  235. IntlIterator_ce_ptr = register_class_IntlIterator(zend_ce_iterator);
  236. IntlIterator_ce_ptr->create_object = IntlIterator_object_create;
  237. IntlIterator_ce_ptr->get_iterator = IntlIterator_get_iterator;
  238. IntlIterator_ce_ptr->ce_flags |= ZEND_ACC_REUSE_GET_ITERATOR;
  239. memcpy(&IntlIterator_handlers, &std_object_handlers,
  240. sizeof IntlIterator_handlers);
  241. IntlIterator_handlers.offset = XtOffsetOf(IntlIterator_object, zo);
  242. IntlIterator_handlers.clone_obj = NULL;
  243. IntlIterator_handlers.free_obj = IntlIterator_objects_free;
  244. }