common_enum.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 7 |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | http://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Authors: Gustavo Lopes <cataphract@php.net> |
  14. +----------------------------------------------------------------------+
  15. */
  16. #ifdef HAVE_CONFIG_H
  17. #include "config.h"
  18. #endif
  19. #include "../intl_cppshims.h"
  20. // Fix build on Windows/old versions of ICU
  21. #include <stdio.h>
  22. #include "common_enum.h"
  23. extern "C" {
  24. #include <zend_interfaces.h>
  25. #include <zend_exceptions.h>
  26. }
  27. zend_class_entry *IntlIterator_ce_ptr;
  28. zend_object_handlers IntlIterator_handlers;
  29. void zoi_with_current_dtor(zend_object_iterator *iter)
  30. {
  31. zoi_with_current *zoiwc = (zoi_with_current*)iter;
  32. if (!Z_ISUNDEF(zoiwc->wrapping_obj)) {
  33. /* we have to copy the pointer because zoiwc->wrapping_obj may be
  34. * changed midway the execution of zval_ptr_dtor() */
  35. zval *zwo = &zoiwc->wrapping_obj;
  36. /* object is still here, we can rely on it to call this again and
  37. * destroy this object */
  38. zval_ptr_dtor(zwo);
  39. } else {
  40. /* Object not here anymore (we've been called by the object free handler)
  41. * Note that the iterator wrapper objects (that also depend on this
  42. * structure) call this function earlier, in the destruction phase, which
  43. * precedes the object free phase. Therefore there's no risk on this
  44. * function being called by the iterator wrapper destructor function and
  45. * not finding the memory of this iterator allocated anymore. */
  46. iter->funcs->invalidate_current(iter);
  47. zoiwc->destroy_it(iter);
  48. }
  49. }
  50. U_CFUNC int zoi_with_current_valid(zend_object_iterator *iter)
  51. {
  52. return Z_ISUNDEF(((zoi_with_current*)iter)->current)? FAILURE : SUCCESS;
  53. }
  54. U_CFUNC zval *zoi_with_current_get_current_data(zend_object_iterator *iter)
  55. {
  56. return &((zoi_with_current*)iter)->current;
  57. }
  58. U_CFUNC void zoi_with_current_invalidate_current(zend_object_iterator *iter)
  59. {
  60. zoi_with_current *zoi_iter = (zoi_with_current*)iter;
  61. if (!Z_ISUNDEF(zoi_iter->current)) {
  62. zval_ptr_dtor(&zoi_iter->current);
  63. ZVAL_UNDEF(&zoi_iter->current); //valid would return FAILURE now
  64. }
  65. }
  66. static void string_enum_current_move_forward(zend_object_iterator *iter)
  67. {
  68. zoi_with_current *zoi_iter = (zoi_with_current*)iter;
  69. INTLITERATOR_METHOD_INIT_VARS;
  70. iter->funcs->invalidate_current(iter);
  71. object = &zoi_iter->wrapping_obj;
  72. INTLITERATOR_METHOD_FETCH_OBJECT_NO_CHECK;
  73. int32_t result_length;
  74. const char *result = ((StringEnumeration*)Z_PTR(iter->data))->next(
  75. &result_length, INTLITERATOR_ERROR_CODE(ii));
  76. intl_error_set_code(NULL, INTLITERATOR_ERROR_CODE(ii));
  77. if (U_FAILURE(INTLITERATOR_ERROR_CODE(ii))) {
  78. intl_errors_set_custom_msg(INTL_DATA_ERROR_P(ii),
  79. "Error fetching next iteration element", 0);
  80. } else if (result) {
  81. ZVAL_STRINGL(&zoi_iter->current, result, result_length);
  82. } //else we've reached the end of the enum, nothing more is required
  83. }
  84. static void string_enum_rewind(zend_object_iterator *iter)
  85. {
  86. zoi_with_current *zoi_iter = (zoi_with_current*)iter;
  87. INTLITERATOR_METHOD_INIT_VARS;
  88. if (!Z_ISUNDEF(zoi_iter->current)) {
  89. iter->funcs->invalidate_current(iter);
  90. }
  91. object = &zoi_iter->wrapping_obj;
  92. INTLITERATOR_METHOD_FETCH_OBJECT_NO_CHECK;
  93. ((StringEnumeration*)Z_PTR(iter->data))->reset(INTLITERATOR_ERROR_CODE(ii));
  94. intl_error_set_code(NULL, INTLITERATOR_ERROR_CODE(ii));
  95. if (U_FAILURE(INTLITERATOR_ERROR_CODE(ii))) {
  96. intl_errors_set_custom_msg(INTL_DATA_ERROR_P(ii),
  97. "Error resetting enumeration", 0);
  98. } else {
  99. iter->funcs->move_forward(iter);
  100. }
  101. }
  102. static void string_enum_destroy_it(zend_object_iterator *iter)
  103. {
  104. delete (StringEnumeration*)Z_PTR(iter->data);
  105. }
  106. static const zend_object_iterator_funcs string_enum_object_iterator_funcs = {
  107. zoi_with_current_dtor,
  108. zoi_with_current_valid,
  109. zoi_with_current_get_current_data,
  110. NULL,
  111. string_enum_current_move_forward,
  112. string_enum_rewind,
  113. zoi_with_current_invalidate_current
  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_COPY_VALUE(&((zoi_with_current*)ii->iterator)->wrapping_obj, 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. static PHP_METHOD(IntlIterator, current)
  169. {
  170. zval *data;
  171. INTLITERATOR_METHOD_INIT_VARS;
  172. if (zend_parse_parameters_none() == FAILURE) {
  173. intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
  174. "IntlIterator::current: bad arguments", 0);
  175. return;
  176. }
  177. INTLITERATOR_METHOD_FETCH_OBJECT;
  178. data = ii->iterator->funcs->get_current_data(ii->iterator);
  179. if (data) {
  180. ZVAL_COPY_DEREF(return_value, data);
  181. }
  182. }
  183. static PHP_METHOD(IntlIterator, key)
  184. {
  185. INTLITERATOR_METHOD_INIT_VARS;
  186. if (zend_parse_parameters_none() == FAILURE) {
  187. intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
  188. "IntlIterator::key: bad arguments", 0);
  189. return;
  190. }
  191. INTLITERATOR_METHOD_FETCH_OBJECT;
  192. if (ii->iterator->funcs->get_current_key) {
  193. ii->iterator->funcs->get_current_key(ii->iterator, return_value);
  194. } else {
  195. RETURN_LONG(ii->iterator->index);
  196. }
  197. }
  198. static PHP_METHOD(IntlIterator, next)
  199. {
  200. INTLITERATOR_METHOD_INIT_VARS;
  201. if (zend_parse_parameters_none() == FAILURE) {
  202. intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
  203. "IntlIterator::next: bad arguments", 0);
  204. return;
  205. }
  206. INTLITERATOR_METHOD_FETCH_OBJECT;
  207. ii->iterator->funcs->move_forward(ii->iterator);
  208. /* foreach also advances the index after the last iteration,
  209. * so I see no problem in incrementing the index here unconditionally */
  210. ii->iterator->index++;
  211. }
  212. static PHP_METHOD(IntlIterator, rewind)
  213. {
  214. INTLITERATOR_METHOD_INIT_VARS;
  215. if (zend_parse_parameters_none() == FAILURE) {
  216. intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
  217. "IntlIterator::rewind: bad arguments", 0);
  218. return;
  219. }
  220. INTLITERATOR_METHOD_FETCH_OBJECT;
  221. if (ii->iterator->funcs->rewind) {
  222. ii->iterator->funcs->rewind(ii->iterator);
  223. } else {
  224. intl_errors_set(INTLITERATOR_ERROR_P(ii), U_UNSUPPORTED_ERROR,
  225. "IntlIterator::rewind: rewind not supported", 0);
  226. }
  227. }
  228. static PHP_METHOD(IntlIterator, valid)
  229. {
  230. INTLITERATOR_METHOD_INIT_VARS;
  231. if (zend_parse_parameters_none() == FAILURE) {
  232. intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
  233. "IntlIterator::valid: bad arguments", 0);
  234. return;
  235. }
  236. INTLITERATOR_METHOD_FETCH_OBJECT;
  237. RETURN_BOOL(ii->iterator->funcs->valid(ii->iterator) == SUCCESS);
  238. }
  239. ZEND_BEGIN_ARG_INFO_EX(ainfo_se_void, 0, 0, 0)
  240. ZEND_END_ARG_INFO()
  241. static const zend_function_entry IntlIterator_class_functions[] = {
  242. PHP_ME(IntlIterator, current, ainfo_se_void, ZEND_ACC_PUBLIC)
  243. PHP_ME(IntlIterator, key, ainfo_se_void, ZEND_ACC_PUBLIC)
  244. PHP_ME(IntlIterator, next, ainfo_se_void, ZEND_ACC_PUBLIC)
  245. PHP_ME(IntlIterator, rewind, ainfo_se_void, ZEND_ACC_PUBLIC)
  246. PHP_ME(IntlIterator, valid, ainfo_se_void, ZEND_ACC_PUBLIC)
  247. PHP_FE_END
  248. };
  249. /* {{{ intl_register_IntlIterator_class
  250. * Initialize 'IntlIterator' class
  251. */
  252. U_CFUNC void intl_register_IntlIterator_class(void)
  253. {
  254. zend_class_entry ce;
  255. /* Create and register 'IntlIterator' class. */
  256. INIT_CLASS_ENTRY(ce, "IntlIterator", IntlIterator_class_functions);
  257. ce.create_object = IntlIterator_object_create;
  258. IntlIterator_ce_ptr = zend_register_internal_class(&ce);
  259. IntlIterator_ce_ptr->get_iterator = IntlIterator_get_iterator;
  260. zend_class_implements(IntlIterator_ce_ptr, 1,
  261. zend_ce_iterator);
  262. memcpy(&IntlIterator_handlers, &std_object_handlers,
  263. sizeof IntlIterator_handlers);
  264. IntlIterator_handlers.offset = XtOffsetOf(IntlIterator_object, zo);
  265. IntlIterator_handlers.clone_obj = NULL;
  266. IntlIterator_handlers.dtor_obj = zend_objects_destroy_object;
  267. IntlIterator_handlers.free_obj = IntlIterator_objects_free;
  268. }