converter.c 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153
  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: Sara Golemon <pollita@php.net> |
  14. +----------------------------------------------------------------------+
  15. */
  16. #include "converter.h"
  17. #include "zend_exceptions.h"
  18. #include <unicode/utypes.h>
  19. #if U_ICU_VERSION_MAJOR_NUM >= 49
  20. #include <unicode/utf8.h>
  21. #include <unicode/utf16.h>
  22. #endif
  23. #include <unicode/ucnv.h>
  24. #include <unicode/ustring.h>
  25. #include "../intl_error.h"
  26. #include "../intl_common.h"
  27. typedef struct _php_converter_object {
  28. UConverter *src, *dest;
  29. zend_fcall_info to_cb, from_cb;
  30. zend_fcall_info_cache to_cache, from_cache;
  31. intl_error error;
  32. zend_object obj;
  33. } php_converter_object;
  34. static inline php_converter_object *php_converter_fetch_object(zend_object *obj) {
  35. return (php_converter_object *)((char*)(obj) - XtOffsetOf(php_converter_object, obj));
  36. }
  37. #define Z_INTL_CONVERTER_P(zv) php_converter_fetch_object(Z_OBJ_P(zv))
  38. static zend_class_entry *php_converter_ce;
  39. static zend_object_handlers php_converter_object_handlers;
  40. #define CONV_GET(pzv) (Z_INTL_CONVERTER_P((pzv)))
  41. #define THROW_UFAILURE(obj, fname, error) php_converter_throw_failure(obj, error, \
  42. fname "() returned error " ZEND_LONG_FMT ": %s", (zend_long)error, u_errorName(error))
  43. /* {{{ php_converter_throw_failure */
  44. static inline void php_converter_throw_failure(php_converter_object *objval, UErrorCode error, const char *format, ...) {
  45. intl_error *err = objval ? &(objval->error) : NULL;
  46. char message[1024];
  47. va_list vargs;
  48. va_start(vargs, format);
  49. vsnprintf(message, sizeof(message), format, vargs);
  50. va_end(vargs);
  51. intl_errors_set(err, error, message, 1);
  52. }
  53. /* }}} */
  54. /* {{{ php_converter_default_callback */
  55. static void php_converter_default_callback(zval *return_value, zval *zobj, zend_long reason, zval *error) {
  56. ZVAL_DEREF(error);
  57. zval_ptr_dtor(error);
  58. ZVAL_LONG(error, U_ZERO_ERROR);
  59. /* Basic functionality so children can call parent::toUCallback() */
  60. switch (reason) {
  61. case UCNV_UNASSIGNED:
  62. case UCNV_ILLEGAL:
  63. case UCNV_IRREGULAR:
  64. {
  65. php_converter_object *objval = (php_converter_object*)CONV_GET(zobj);
  66. char chars[127];
  67. int8_t chars_len = sizeof(chars);
  68. UErrorCode uerror = U_ZERO_ERROR;
  69. if(!objval->src) {
  70. php_converter_throw_failure(objval, U_INVALID_STATE_ERROR, "Source Converter has not been initialized yet");
  71. chars[0] = 0x1A;
  72. chars[1] = 0;
  73. chars_len = 1;
  74. ZVAL_LONG(error, U_INVALID_STATE_ERROR);
  75. RETVAL_STRINGL(chars, chars_len);
  76. return;
  77. }
  78. /* Yes, this is fairly wasteful at first glance,
  79. * but considering that the alternative is to store
  80. * what's sent into setSubstChars() and the fact
  81. * that this is an extremely unlikely codepath
  82. * I'd rather take the CPU hit here, than waste time
  83. * storing a value I'm unlikely to use.
  84. */
  85. ucnv_getSubstChars(objval->src, chars, &chars_len, &uerror);
  86. if (U_FAILURE(uerror)) {
  87. THROW_UFAILURE(objval, "ucnv_getSubstChars", uerror);
  88. chars[0] = 0x1A;
  89. chars[1] = 0;
  90. chars_len = 1;
  91. ZVAL_LONG(error, uerror);
  92. }
  93. RETVAL_STRINGL(chars, chars_len);
  94. }
  95. }
  96. }
  97. /* }}} */
  98. /* {{{ proto void UConverter::toUCallback(int $reason,
  99. string $source, string $codeUnits,
  100. int &$error) */
  101. ZEND_BEGIN_ARG_INFO_EX(php_converter_toUCallback_arginfo, 0, ZEND_RETURN_VALUE, 4)
  102. ZEND_ARG_INFO(0, reason)
  103. ZEND_ARG_INFO(0, source)
  104. ZEND_ARG_INFO(0, codeUnits)
  105. ZEND_ARG_INFO(1, error)
  106. ZEND_END_ARG_INFO();
  107. static PHP_METHOD(UConverter, toUCallback) {
  108. zend_long reason;
  109. zval *source, *codeUnits, *error;
  110. if (zend_parse_parameters(ZEND_NUM_ARGS(), "lzzz",
  111. &reason, &source, &codeUnits, &error) == FAILURE) {
  112. return;
  113. }
  114. php_converter_default_callback(return_value, getThis(), reason, error);
  115. }
  116. /* }}} */
  117. /* {{{ proto void UConverter::fromUCallback(int $reason,
  118. Array $source, int $codePoint,
  119. int &$error) */
  120. ZEND_BEGIN_ARG_INFO_EX(php_converter_fromUCallback_arginfo, 0, ZEND_RETURN_VALUE, 4)
  121. ZEND_ARG_INFO(0, reason)
  122. ZEND_ARG_INFO(0, source)
  123. ZEND_ARG_INFO(0, codePoint)
  124. ZEND_ARG_INFO(1, error)
  125. ZEND_END_ARG_INFO();
  126. static PHP_METHOD(UConverter, fromUCallback) {
  127. zend_long reason;
  128. zval *source, *codePoint, *error;
  129. if (zend_parse_parameters(ZEND_NUM_ARGS(), "lzzz",
  130. &reason, &source, &codePoint, &error) == FAILURE) {
  131. return;
  132. }
  133. php_converter_default_callback(return_value, getThis(), reason, error);
  134. }
  135. /* }}} */
  136. /* {{{ php_converter_check_limits */
  137. static inline zend_bool php_converter_check_limits(php_converter_object *objval, zend_long available, zend_long needed) {
  138. if (available < needed) {
  139. php_converter_throw_failure(objval, U_BUFFER_OVERFLOW_ERROR, "Buffer overrun " ZEND_LONG_FMT " bytes needed, " ZEND_LONG_FMT " available", needed, available);
  140. return 0;
  141. }
  142. return 1;
  143. }
  144. /* }}} */
  145. #define TARGET_CHECK(cnvargs, needed) php_converter_check_limits(objval, cnvargs->targetLimit - cnvargs->target, needed)
  146. /* {{{ php_converter_append_toUnicode_target */
  147. static void php_converter_append_toUnicode_target(zval *val, UConverterToUnicodeArgs *args, php_converter_object *objval) {
  148. switch (Z_TYPE_P(val)) {
  149. case IS_NULL:
  150. /* Code unit is being skipped */
  151. return;
  152. case IS_LONG:
  153. {
  154. zend_long lval = Z_LVAL_P(val);
  155. if ((lval < 0) || (lval > 0x10FFFF)) {
  156. php_converter_throw_failure(objval, U_ILLEGAL_ARGUMENT_ERROR, "Invalid codepoint U+%04lx", lval);
  157. return;
  158. }
  159. if (lval > 0xFFFF) {
  160. /* Supplemental planes U+010000 - U+10FFFF */
  161. if (TARGET_CHECK(args, 2)) {
  162. /* TODO: Find the ICU call which does this properly */
  163. *(args->target++) = (UChar)(((lval - 0x10000) >> 10) | 0xD800);
  164. *(args->target++) = (UChar)(((lval - 0x10000) & 0x3FF) | 0xDC00);
  165. }
  166. return;
  167. }
  168. /* Non-suggogate BMP codepoint */
  169. if (TARGET_CHECK(args, 1)) {
  170. *(args->target++) = (UChar)lval;
  171. }
  172. return;
  173. }
  174. case IS_STRING:
  175. {
  176. const char *strval = Z_STRVAL_P(val);
  177. int i = 0, strlen = Z_STRLEN_P(val);
  178. while((i != strlen) && TARGET_CHECK(args, 1)) {
  179. UChar c;
  180. U8_NEXT(strval, i, strlen, c);
  181. *(args->target++) = c;
  182. }
  183. return;
  184. }
  185. case IS_ARRAY:
  186. {
  187. HashTable *ht = Z_ARRVAL_P(val);
  188. zval *tmpzval;
  189. ZEND_HASH_FOREACH_VAL(ht, tmpzval) {
  190. php_converter_append_toUnicode_target(tmpzval, args, objval);
  191. } ZEND_HASH_FOREACH_END();
  192. return;
  193. }
  194. default:
  195. php_converter_throw_failure(objval, U_ILLEGAL_ARGUMENT_ERROR,
  196. "toUCallback() specified illegal type for substitution character");
  197. }
  198. }
  199. /* }}} */
  200. /* {{{ php_converter_to_u_callback */
  201. static void php_converter_to_u_callback(const void *context,
  202. UConverterToUnicodeArgs *args,
  203. const char *codeUnits, int32_t length,
  204. UConverterCallbackReason reason,
  205. UErrorCode *pErrorCode) {
  206. php_converter_object *objval = (php_converter_object*)context;
  207. zval retval;
  208. zval zargs[4];
  209. ZVAL_LONG(&zargs[0], reason);
  210. ZVAL_STRINGL(&zargs[1], args->source, args->sourceLimit - args->source);
  211. ZVAL_STRINGL(&zargs[2], codeUnits, length);
  212. ZVAL_LONG(&zargs[3], *pErrorCode);
  213. objval->to_cb.param_count = 4;
  214. objval->to_cb.params = zargs;
  215. objval->to_cb.retval = &retval;
  216. objval->to_cb.no_separation = 0;
  217. if (zend_call_function(&(objval->to_cb), &(objval->to_cache)) == FAILURE) {
  218. /* Unlikely */
  219. php_converter_throw_failure(objval, U_INTERNAL_PROGRAM_ERROR, "Unexpected failure calling toUCallback()");
  220. } else if (!Z_ISUNDEF(retval)) {
  221. php_converter_append_toUnicode_target(&retval, args, objval);
  222. zval_ptr_dtor(&retval);
  223. }
  224. if (Z_TYPE(zargs[3]) == IS_LONG) {
  225. *pErrorCode = Z_LVAL(zargs[3]);
  226. } else if (Z_ISREF(zargs[3]) && Z_TYPE_P(Z_REFVAL(zargs[3])) == IS_LONG) {
  227. *pErrorCode = Z_LVAL_P(Z_REFVAL(zargs[3]));
  228. }
  229. zval_ptr_dtor(&zargs[0]);
  230. zval_ptr_dtor(&zargs[1]);
  231. zval_ptr_dtor(&zargs[2]);
  232. zval_ptr_dtor(&zargs[3]);
  233. }
  234. /* }}} */
  235. /* {{{ php_converter_append_fromUnicode_target */
  236. static void php_converter_append_fromUnicode_target(zval *val, UConverterFromUnicodeArgs *args, php_converter_object *objval) {
  237. switch (Z_TYPE_P(val)) {
  238. case IS_NULL:
  239. /* Ignore */
  240. return;
  241. case IS_LONG:
  242. if (TARGET_CHECK(args, 1)) {
  243. *(args->target++) = Z_LVAL_P(val);
  244. }
  245. return;
  246. case IS_STRING:
  247. {
  248. size_t vallen = Z_STRLEN_P(val);
  249. if (TARGET_CHECK(args, vallen)) {
  250. memcpy(args->target, Z_STRVAL_P(val), vallen);
  251. args->target += vallen;
  252. }
  253. return;
  254. }
  255. case IS_ARRAY:
  256. {
  257. HashTable *ht = Z_ARRVAL_P(val);
  258. zval *tmpzval;
  259. ZEND_HASH_FOREACH_VAL(ht, tmpzval) {
  260. php_converter_append_fromUnicode_target(tmpzval, args, objval);
  261. } ZEND_HASH_FOREACH_END();
  262. return;
  263. }
  264. default:
  265. php_converter_throw_failure(objval, U_ILLEGAL_ARGUMENT_ERROR, "fromUCallback() specified illegal type for substitution character");
  266. }
  267. }
  268. /* }}} */
  269. /* {{{ php_converter_from_u_callback */
  270. static void php_converter_from_u_callback(const void *context,
  271. UConverterFromUnicodeArgs *args,
  272. const UChar *codeUnits, int32_t length, UChar32 codePoint,
  273. UConverterCallbackReason reason,
  274. UErrorCode *pErrorCode) {
  275. php_converter_object *objval = (php_converter_object*)context;
  276. zval retval;
  277. zval zargs[4];
  278. int i;
  279. ZVAL_LONG(&zargs[0], reason);
  280. array_init(&zargs[1]);
  281. i = 0;
  282. while (i < length) {
  283. UChar32 c;
  284. U16_NEXT(codeUnits, i, length, c);
  285. add_next_index_long(&zargs[1], c);
  286. }
  287. ZVAL_LONG(&zargs[2], codePoint);
  288. ZVAL_LONG(&zargs[3], *pErrorCode);
  289. objval->from_cb.param_count = 4;
  290. objval->from_cb.params = zargs;
  291. objval->from_cb.retval = &retval;
  292. objval->from_cb.no_separation = 0;
  293. if (zend_call_function(&(objval->from_cb), &(objval->from_cache)) == FAILURE) {
  294. /* Unlikely */
  295. php_converter_throw_failure(objval, U_INTERNAL_PROGRAM_ERROR, "Unexpected failure calling fromUCallback()");
  296. } else if (!Z_ISUNDEF(retval)) {
  297. php_converter_append_fromUnicode_target(&retval, args, objval);
  298. zval_ptr_dtor(&retval);
  299. }
  300. if (Z_TYPE(zargs[3]) == IS_LONG) {
  301. *pErrorCode = Z_LVAL(zargs[3]);
  302. } else if (Z_ISREF(zargs[3]) && Z_TYPE_P(Z_REFVAL(zargs[3])) == IS_LONG) {
  303. *pErrorCode = Z_LVAL_P(Z_REFVAL(zargs[3]));
  304. }
  305. zval_ptr_dtor(&zargs[0]);
  306. zval_ptr_dtor(&zargs[1]);
  307. zval_ptr_dtor(&zargs[2]);
  308. zval_ptr_dtor(&zargs[3]);
  309. }
  310. /* }}} */
  311. /* {{{ php_converter_set_callbacks */
  312. static inline zend_bool php_converter_set_callbacks(php_converter_object *objval, UConverter *cnv) {
  313. zend_bool ret = 1;
  314. UErrorCode error = U_ZERO_ERROR;
  315. if (objval->obj.ce == php_converter_ce) {
  316. /* Short-circuit having to go through method calls and data marshalling
  317. * when we're using default behavior
  318. */
  319. return 1;
  320. }
  321. ucnv_setToUCallBack(cnv, (UConverterToUCallback)php_converter_to_u_callback, (const void*)objval,
  322. NULL, NULL, &error);
  323. if (U_FAILURE(error)) {
  324. THROW_UFAILURE(objval, "ucnv_setToUCallBack", error);
  325. ret = 0;
  326. }
  327. error = U_ZERO_ERROR;
  328. ucnv_setFromUCallBack(cnv, (UConverterFromUCallback)php_converter_from_u_callback, (const void*)objval,
  329. NULL, NULL, &error);
  330. if (U_FAILURE(error)) {
  331. THROW_UFAILURE(objval, "ucnv_setFromUCallBack", error);
  332. ret = 0;
  333. }
  334. return ret;
  335. }
  336. /* }}} */
  337. /* {{{ php_converter_set_encoding */
  338. static zend_bool php_converter_set_encoding(php_converter_object *objval,
  339. UConverter **pcnv,
  340. const char *enc, size_t enc_len
  341. ) {
  342. UErrorCode error = U_ZERO_ERROR;
  343. UConverter *cnv = ucnv_open(enc, &error);
  344. if (error == U_AMBIGUOUS_ALIAS_WARNING) {
  345. UErrorCode getname_error = U_ZERO_ERROR;
  346. const char *actual_encoding = ucnv_getName(cnv, &getname_error);
  347. if (U_FAILURE(getname_error)) {
  348. /* Should never happen */
  349. actual_encoding = "(unknown)";
  350. }
  351. php_error_docref(NULL, E_WARNING, "Ambiguous encoding specified, using %s", actual_encoding);
  352. } else if (U_FAILURE(error)) {
  353. if (objval) {
  354. THROW_UFAILURE(objval, "ucnv_open", error);
  355. } else {
  356. php_error_docref(NULL, E_WARNING, "Error setting encoding: %d - %s", (int)error, u_errorName(error));
  357. }
  358. return 0;
  359. }
  360. if (objval && !php_converter_set_callbacks(objval, cnv)) {
  361. return 0;
  362. }
  363. if (*pcnv) {
  364. ucnv_close(*pcnv);
  365. }
  366. *pcnv = cnv;
  367. return 1;
  368. }
  369. /* }}} */
  370. /* {{{ php_converter_do_set_encoding */
  371. ZEND_BEGIN_ARG_INFO_EX(php_converter_set_encoding_arginfo, 0, ZEND_RETURN_VALUE, 1)
  372. ZEND_ARG_INFO(0, encoding)
  373. ZEND_END_ARG_INFO();
  374. static void php_converter_do_set_encoding(UConverter **pcnv, INTERNAL_FUNCTION_PARAMETERS) {
  375. php_converter_object *objval = CONV_GET(getThis());
  376. char *enc;
  377. size_t enc_len;
  378. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &enc, &enc_len) == FAILURE) {
  379. intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "Bad arguments, "
  380. "expected one string argument", 0);
  381. RETURN_FALSE;
  382. }
  383. intl_errors_reset(&objval->error);
  384. RETURN_BOOL(php_converter_set_encoding(objval, pcnv, enc, enc_len));
  385. }
  386. /* }}} */
  387. /* {{{ proto bool UConverter::setSourceEncoding(string encoding) */
  388. static PHP_METHOD(UConverter, setSourceEncoding) {
  389. php_converter_object *objval = CONV_GET(getThis());
  390. php_converter_do_set_encoding(&(objval->src), INTERNAL_FUNCTION_PARAM_PASSTHRU);
  391. }
  392. /* }}} */
  393. /* {{{ proto bool UConverter::setDestinationEncoding(string encoding) */
  394. static PHP_METHOD(UConverter, setDestinationEncoding) {
  395. php_converter_object *objval = CONV_GET(getThis());
  396. php_converter_do_set_encoding(&(objval->dest), INTERNAL_FUNCTION_PARAM_PASSTHRU);
  397. }
  398. /* }}} */
  399. /* {{{ php_converter_do_get_encoding */
  400. ZEND_BEGIN_ARG_INFO_EX(php_converter_get_encoding_arginfo, 0, ZEND_RETURN_VALUE, 0)
  401. ZEND_END_ARG_INFO();
  402. static void php_converter_do_get_encoding(php_converter_object *objval, UConverter *cnv, INTERNAL_FUNCTION_PARAMETERS) {
  403. const char *name;
  404. if (zend_parse_parameters_none() == FAILURE) {
  405. intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "Expected no arguments", 0);
  406. RETURN_FALSE;
  407. }
  408. intl_errors_reset(&objval->error);
  409. if (!cnv) {
  410. RETURN_NULL();
  411. }
  412. name = ucnv_getName(cnv, &objval->error.code);
  413. if (U_FAILURE(objval->error.code)) {
  414. THROW_UFAILURE(objval, "ucnv_getName()", objval->error.code);
  415. RETURN_FALSE;
  416. }
  417. RETURN_STRING(name);
  418. }
  419. /* }}} */
  420. /* {{{ proto string UConverter::getSourceEncoding() */
  421. static PHP_METHOD(UConverter, getSourceEncoding) {
  422. php_converter_object *objval = CONV_GET(getThis());
  423. php_converter_do_get_encoding(objval, objval->src, INTERNAL_FUNCTION_PARAM_PASSTHRU);
  424. }
  425. /* }}} */
  426. /* {{{ proto string UConverter::getDestinationEncoding() */
  427. static PHP_METHOD(UConverter, getDestinationEncoding) {
  428. php_converter_object *objval = CONV_GET(getThis());
  429. php_converter_do_get_encoding(objval, objval->dest, INTERNAL_FUNCTION_PARAM_PASSTHRU);
  430. }
  431. /* }}} */
  432. /* {{{ php_converter_do_get_type */
  433. ZEND_BEGIN_ARG_INFO_EX(php_converter_get_type_arginfo, 0, ZEND_RETURN_VALUE, 0)
  434. ZEND_END_ARG_INFO();
  435. static void php_converter_do_get_type(php_converter_object *objval, UConverter *cnv, INTERNAL_FUNCTION_PARAMETERS) {
  436. UConverterType t;
  437. if (zend_parse_parameters_none() == FAILURE) {
  438. intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "Expected no arguments", 0);
  439. RETURN_FALSE;
  440. }
  441. intl_errors_reset(&objval->error);
  442. if (!cnv) {
  443. RETURN_NULL();
  444. }
  445. t = ucnv_getType(cnv);
  446. if (U_FAILURE(objval->error.code)) {
  447. THROW_UFAILURE(objval, "ucnv_getType", objval->error.code);
  448. RETURN_FALSE;
  449. }
  450. RETURN_LONG(t);
  451. }
  452. /* }}} */
  453. /* {{{ proto int UConverter::getSourceType() */
  454. static PHP_METHOD(UConverter, getSourceType) {
  455. php_converter_object *objval = CONV_GET(getThis());
  456. php_converter_do_get_type(objval, objval->src, INTERNAL_FUNCTION_PARAM_PASSTHRU);
  457. }
  458. /* }}} */
  459. /* {{{ proto int UConverter::getDestinationType() */
  460. static PHP_METHOD(UConverter, getDestinationType) {
  461. php_converter_object *objval = CONV_GET(getThis());
  462. php_converter_do_get_type(objval, objval->dest, INTERNAL_FUNCTION_PARAM_PASSTHRU);
  463. }
  464. /* }}} */
  465. /* {{{ php_converter_resolve_callback */
  466. static void php_converter_resolve_callback(zval *zobj,
  467. php_converter_object *objval,
  468. const char *callback_name,
  469. zend_fcall_info *finfo,
  470. zend_fcall_info_cache *fcache) {
  471. char *errstr = NULL;
  472. zval caller;
  473. array_init(&caller);
  474. Z_ADDREF_P(zobj);
  475. add_index_zval(&caller, 0, zobj);
  476. add_index_string(&caller, 1, callback_name);
  477. if (zend_fcall_info_init(&caller, 0, finfo, fcache, NULL, &errstr) == FAILURE) {
  478. php_converter_throw_failure(objval, U_INTERNAL_PROGRAM_ERROR, "Error setting converter callback: %s", errstr);
  479. }
  480. zend_array_destroy(Z_ARR(caller));
  481. ZVAL_UNDEF(&finfo->function_name);
  482. if (errstr) {
  483. efree(errstr);
  484. }
  485. }
  486. /* }}} */
  487. /* {{{ proto UConverter::__construct([string dest = 'utf-8',[string src = 'utf-8']]) */
  488. ZEND_BEGIN_ARG_INFO_EX(php_converter_arginfo, 0, ZEND_RETURN_VALUE, 0)
  489. ZEND_ARG_INFO(0, destination_encoding)
  490. ZEND_ARG_INFO(0, source_encoding)
  491. ZEND_END_ARG_INFO();
  492. static PHP_METHOD(UConverter, __construct) {
  493. php_converter_object *objval = CONV_GET(getThis());
  494. char *src = "utf-8";
  495. size_t src_len = sizeof("utf-8") - 1;
  496. char *dest = src;
  497. size_t dest_len = src_len;
  498. intl_error_reset(NULL);
  499. if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "|s!s!", &dest, &dest_len, &src, &src_len) == FAILURE) {
  500. return;
  501. }
  502. php_converter_set_encoding(objval, &(objval->src), src, src_len );
  503. php_converter_set_encoding(objval, &(objval->dest), dest, dest_len);
  504. php_converter_resolve_callback(getThis(), objval, "toUCallback", &(objval->to_cb), &(objval->to_cache));
  505. php_converter_resolve_callback(getThis(), objval, "fromUCallback", &(objval->from_cb), &(objval->from_cache));
  506. }
  507. /* }}} */
  508. /* {{{ proto bool UConverter::setSubstChars(string $chars) */
  509. ZEND_BEGIN_ARG_INFO_EX(php_converter_setSubstChars_arginfo, 0, ZEND_RETURN_VALUE, 1)
  510. ZEND_ARG_INFO(0, chars)
  511. ZEND_END_ARG_INFO();
  512. static PHP_METHOD(UConverter, setSubstChars) {
  513. php_converter_object *objval = CONV_GET(getThis());
  514. char *chars;
  515. size_t chars_len;
  516. int ret = 1;
  517. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &chars, &chars_len) == FAILURE) {
  518. intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
  519. "UConverter::setSubstChars(): bad arguments", 0);
  520. RETURN_FALSE;
  521. }
  522. intl_errors_reset(&objval->error);
  523. if (objval->src) {
  524. UErrorCode error = U_ZERO_ERROR;
  525. ucnv_setSubstChars(objval->src, chars, chars_len, &error);
  526. if (U_FAILURE(error)) {
  527. THROW_UFAILURE(objval, "ucnv_setSubstChars", error);
  528. ret = 0;
  529. }
  530. } else {
  531. php_converter_throw_failure(objval, U_INVALID_STATE_ERROR, "Source Converter has not been initialized yet");
  532. ret = 0;
  533. }
  534. if (objval->dest) {
  535. UErrorCode error = U_ZERO_ERROR;
  536. ucnv_setSubstChars(objval->dest, chars, chars_len, &error);
  537. if (U_FAILURE(error)) {
  538. THROW_UFAILURE(objval, "ucnv_setSubstChars", error);
  539. ret = 0;
  540. }
  541. } else {
  542. php_converter_throw_failure(objval, U_INVALID_STATE_ERROR, "Destination Converter has not been initialized yet");
  543. ret = 0;
  544. }
  545. RETURN_BOOL(ret);
  546. }
  547. /* }}} */
  548. /* {{{ proto string UConverter::getSubstChars() */
  549. ZEND_BEGIN_ARG_INFO_EX(php_converter_getSubstChars_arginfo, 0, ZEND_RETURN_VALUE, 0)
  550. ZEND_END_ARG_INFO();
  551. static PHP_METHOD(UConverter, getSubstChars) {
  552. php_converter_object *objval = CONV_GET(getThis());
  553. char chars[127];
  554. int8_t chars_len = sizeof(chars);
  555. UErrorCode error = U_ZERO_ERROR;
  556. if (zend_parse_parameters_none() == FAILURE) {
  557. intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
  558. "UConverter::getSubstChars(): expected no arguments", 0);
  559. RETURN_FALSE;
  560. }
  561. intl_errors_reset(&objval->error);
  562. if (!objval->src) {
  563. RETURN_NULL();
  564. }
  565. /* src and dest get the same subst chars set,
  566. * so it doesn't really matter which one we read from
  567. */
  568. ucnv_getSubstChars(objval->src, chars, &chars_len, &error);
  569. if (U_FAILURE(error)) {
  570. THROW_UFAILURE(objval, "ucnv_getSubstChars", error);
  571. RETURN_FALSE;
  572. }
  573. RETURN_STRINGL(chars, chars_len);
  574. }
  575. /* }}} */
  576. /* {{{ php_converter_do_convert */
  577. static zend_string* php_converter_do_convert(UConverter *dest_cnv,
  578. UConverter *src_cnv, const char *src, int32_t src_len,
  579. php_converter_object *objval
  580. ) {
  581. UErrorCode error = U_ZERO_ERROR;
  582. int32_t temp_len, ret_len;
  583. zend_string *ret;
  584. UChar *temp;
  585. if (!src_cnv || !dest_cnv) {
  586. php_converter_throw_failure(objval, U_INVALID_STATE_ERROR,
  587. "Internal converters not initialized");
  588. return NULL;
  589. }
  590. /* Get necessary buffer size first */
  591. temp_len = 1 + ucnv_toUChars(src_cnv, NULL, 0, src, src_len, &error);
  592. if (U_FAILURE(error) && error != U_BUFFER_OVERFLOW_ERROR) {
  593. THROW_UFAILURE(objval, "ucnv_toUChars", error);
  594. return NULL;
  595. }
  596. temp = safe_emalloc(sizeof(UChar), temp_len, sizeof(UChar));
  597. /* Convert to intermediate UChar* array */
  598. error = U_ZERO_ERROR;
  599. temp_len = ucnv_toUChars(src_cnv, temp, temp_len, src, src_len, &error);
  600. if (U_FAILURE(error)) {
  601. THROW_UFAILURE(objval, "ucnv_toUChars", error);
  602. efree(temp);
  603. return NULL;
  604. }
  605. temp[temp_len] = 0;
  606. /* Get necessary output buffer size */
  607. ret_len = ucnv_fromUChars(dest_cnv, NULL, 0, temp, temp_len, &error);
  608. if (U_FAILURE(error) && error != U_BUFFER_OVERFLOW_ERROR) {
  609. THROW_UFAILURE(objval, "ucnv_fromUChars", error);
  610. efree(temp);
  611. return NULL;
  612. }
  613. ret = zend_string_alloc(ret_len, 0);
  614. /* Convert to final encoding */
  615. error = U_ZERO_ERROR;
  616. ZSTR_LEN(ret) = ucnv_fromUChars(dest_cnv, ZSTR_VAL(ret), ret_len+1, temp, temp_len, &error);
  617. efree(temp);
  618. if (U_FAILURE(error)) {
  619. THROW_UFAILURE(objval, "ucnv_fromUChars", error);
  620. zend_string_efree(ret);
  621. return NULL;
  622. }
  623. return ret;
  624. }
  625. /* }}} */
  626. /* {{{ proto string UConverter::reasonText(int reason) */
  627. #define UCNV_REASON_CASE(v) case (UCNV_ ## v) : RETURN_STRINGL( "REASON_" #v , sizeof( "REASON_" #v ) - 1);
  628. ZEND_BEGIN_ARG_INFO_EX(php_converter_reasontext_arginfo, 0, ZEND_RETURN_VALUE, 0)
  629. ZEND_ARG_INFO(0, reason)
  630. ZEND_END_ARG_INFO();
  631. static PHP_METHOD(UConverter, reasonText) {
  632. zend_long reason;
  633. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &reason) == FAILURE) {
  634. intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
  635. "UConverter::reasonText(): bad arguments", 0);
  636. RETURN_FALSE;
  637. }
  638. intl_error_reset(NULL);
  639. switch (reason) {
  640. UCNV_REASON_CASE(UNASSIGNED)
  641. UCNV_REASON_CASE(ILLEGAL)
  642. UCNV_REASON_CASE(IRREGULAR)
  643. UCNV_REASON_CASE(RESET)
  644. UCNV_REASON_CASE(CLOSE)
  645. UCNV_REASON_CASE(CLONE)
  646. default:
  647. php_error_docref(NULL, E_WARNING, "Unknown UConverterCallbackReason: " ZEND_LONG_FMT, reason);
  648. RETURN_FALSE;
  649. }
  650. }
  651. /* }}} */
  652. /* {{{ proto string UConverter::convert(string str[, bool reverse]) */
  653. ZEND_BEGIN_ARG_INFO_EX(php_converter_convert_arginfo, 0, ZEND_RETURN_VALUE, 1)
  654. ZEND_ARG_INFO(0, str)
  655. ZEND_ARG_INFO(0, reverse)
  656. ZEND_END_ARG_INFO();
  657. static PHP_METHOD(UConverter, convert) {
  658. php_converter_object *objval = CONV_GET(getThis());
  659. char *str;
  660. size_t str_len;
  661. zend_string *ret;
  662. zend_bool reverse = 0;
  663. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|b",
  664. &str, &str_len, &reverse) == FAILURE) {
  665. intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
  666. "UConverter::convert(): bad arguments", 0);
  667. RETURN_FALSE;
  668. }
  669. intl_errors_reset(&objval->error);
  670. ret = php_converter_do_convert(reverse ? objval->src : objval->dest,
  671. reverse ? objval->dest : objval->src,
  672. str, str_len,
  673. objval);
  674. if (ret) {
  675. RETURN_NEW_STR(ret);
  676. } else {
  677. RETURN_FALSE;
  678. }
  679. }
  680. /* }}} */
  681. /* {{{ proto string UConverter::transcode(string $str, string $toEncoding, string $fromEncoding[, Array $options = array()]) */
  682. ZEND_BEGIN_ARG_INFO_EX(php_converter_transcode_arginfo, 0, ZEND_RETURN_VALUE, 3)
  683. ZEND_ARG_INFO(0, str)
  684. ZEND_ARG_INFO(0, toEncoding)
  685. ZEND_ARG_INFO(0, fromEncoding)
  686. ZEND_ARG_ARRAY_INFO(0, options, 1)
  687. ZEND_END_ARG_INFO();
  688. static PHP_METHOD(UConverter, transcode) {
  689. char *str, *src, *dest;
  690. size_t str_len, src_len, dest_len;
  691. zval *options = NULL;
  692. UConverter *src_cnv = NULL, *dest_cnv = NULL;
  693. if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss|a!",
  694. &str, &str_len, &dest, &dest_len, &src, &src_len, &options) == FAILURE) {
  695. intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
  696. "UConverter::transcode(): bad arguments", 0);
  697. RETURN_FALSE;
  698. }
  699. intl_error_reset(NULL);
  700. if (php_converter_set_encoding(NULL, &src_cnv, src, src_len) &&
  701. php_converter_set_encoding(NULL, &dest_cnv, dest, dest_len)) {
  702. zend_string *ret;
  703. UErrorCode error = U_ZERO_ERROR;
  704. if (options && zend_hash_num_elements(Z_ARRVAL_P(options))) {
  705. zval *tmpzval;
  706. if (U_SUCCESS(error) &&
  707. (tmpzval = zend_hash_str_find(Z_ARRVAL_P(options), "from_subst", sizeof("from_subst") - 1)) != NULL &&
  708. Z_TYPE_P(tmpzval) == IS_STRING) {
  709. error = U_ZERO_ERROR;
  710. ucnv_setSubstChars(src_cnv, Z_STRVAL_P(tmpzval), Z_STRLEN_P(tmpzval) & 0x7F, &error);
  711. }
  712. if (U_SUCCESS(error) &&
  713. (tmpzval = zend_hash_str_find(Z_ARRVAL_P(options), "to_subst", sizeof("to_subst") - 1)) != NULL &&
  714. Z_TYPE_P(tmpzval) == IS_STRING) {
  715. error = U_ZERO_ERROR;
  716. ucnv_setSubstChars(dest_cnv, Z_STRVAL_P(tmpzval), Z_STRLEN_P(tmpzval) & 0x7F, &error);
  717. }
  718. }
  719. if (U_SUCCESS(error) &&
  720. (ret = php_converter_do_convert(dest_cnv, src_cnv, str, str_len, NULL)) != NULL) {
  721. RETURN_NEW_STR(ret);
  722. }
  723. if (U_FAILURE(error)) {
  724. THROW_UFAILURE(NULL, "transcode", error);
  725. RETVAL_FALSE;
  726. }
  727. } else {
  728. RETVAL_FALSE;
  729. }
  730. if (src_cnv) {
  731. ucnv_close(src_cnv);
  732. }
  733. if (dest_cnv) {
  734. ucnv_close(dest_cnv);
  735. }
  736. }
  737. /* }}} */
  738. /* {{{ proto int UConverter::getErrorCode() */
  739. ZEND_BEGIN_ARG_INFO_EX(php_converter_geterrorcode_arginfo, 0, ZEND_RETURN_VALUE, 0)
  740. ZEND_END_ARG_INFO();
  741. static PHP_METHOD(UConverter, getErrorCode) {
  742. php_converter_object *objval = CONV_GET(getThis());
  743. if (zend_parse_parameters_none() == FAILURE) {
  744. intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
  745. "UConverter::getErrorCode(): expected no arguments", 0);
  746. RETURN_FALSE;
  747. }
  748. RETURN_LONG(intl_error_get_code(&(objval->error)));
  749. }
  750. /* }}} */
  751. /* {{{ proto string UConverter::getErrorMessage() */
  752. ZEND_BEGIN_ARG_INFO_EX(php_converter_geterrormsg_arginfo, 0, ZEND_RETURN_VALUE, 0)
  753. ZEND_END_ARG_INFO();
  754. static PHP_METHOD(UConverter, getErrorMessage) {
  755. php_converter_object *objval = CONV_GET(getThis());
  756. zend_string *message = intl_error_get_message(&(objval->error));
  757. if (zend_parse_parameters_none() == FAILURE) {
  758. intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
  759. "UConverter::getErrorMessage(): expected no arguments", 0);
  760. RETURN_FALSE;
  761. }
  762. if (message) {
  763. RETURN_STR(message);
  764. } else {
  765. RETURN_NULL();
  766. }
  767. }
  768. /* }}} */
  769. /* {{{ proto array UConverter::getAvailable() */
  770. ZEND_BEGIN_ARG_INFO_EX(php_converter_getavailable_arginfo, 0, ZEND_RETURN_VALUE, 0)
  771. ZEND_END_ARG_INFO();
  772. static PHP_METHOD(UConverter, getAvailable) {
  773. int32_t i,
  774. count = ucnv_countAvailable();
  775. if (zend_parse_parameters_none() == FAILURE) {
  776. intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
  777. "UConverter::getErrorMessage(): expected no arguments", 0);
  778. RETURN_FALSE;
  779. }
  780. intl_error_reset(NULL);
  781. array_init(return_value);
  782. for(i = 0; i < count; i++) {
  783. const char *name = ucnv_getAvailableName(i);
  784. add_next_index_string(return_value, name);
  785. }
  786. }
  787. /* }}} */
  788. /* {{{ proto array UConverter::getAliases(string name) */
  789. ZEND_BEGIN_ARG_INFO_EX(php_converter_getaliases_arginfo, 0, ZEND_RETURN_VALUE, 1)
  790. ZEND_ARG_INFO(0, name)
  791. ZEND_END_ARG_INFO();
  792. static PHP_METHOD(UConverter, getAliases) {
  793. char *name;
  794. size_t name_len;
  795. UErrorCode error = U_ZERO_ERROR;
  796. uint16_t i, count;
  797. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
  798. intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
  799. "UConverter::getAliases(): bad arguments", 0);
  800. RETURN_FALSE;
  801. }
  802. intl_error_reset(NULL);
  803. count = ucnv_countAliases(name, &error);
  804. if (U_FAILURE(error)) {
  805. THROW_UFAILURE(NULL, "ucnv_countAliases", error);
  806. RETURN_FALSE;
  807. }
  808. array_init(return_value);
  809. for(i = 0; i < count; i++) {
  810. const char *alias;
  811. error = U_ZERO_ERROR;
  812. alias = ucnv_getAlias(name, i, &error);
  813. if (U_FAILURE(error)) {
  814. THROW_UFAILURE(NULL, "ucnv_getAlias", error);
  815. zend_array_destroy(Z_ARR_P(return_value));
  816. RETURN_NULL();
  817. }
  818. add_next_index_string(return_value, alias);
  819. }
  820. }
  821. /* }}} */
  822. /* {{{ proto array UConverter::getStandards() */
  823. ZEND_BEGIN_ARG_INFO_EX(php_converter_getstandards_arginfo, 0, ZEND_RETURN_VALUE, 0)
  824. ZEND_END_ARG_INFO();
  825. static PHP_METHOD(UConverter, getStandards) {
  826. uint16_t i, count;
  827. if (zend_parse_parameters_none() == FAILURE) {
  828. intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
  829. "UConverter::getStandards(): expected no arguments", 0);
  830. RETURN_FALSE;
  831. }
  832. intl_error_reset(NULL);
  833. array_init(return_value);
  834. count = ucnv_countStandards();
  835. for(i = 0; i < count; i++) {
  836. UErrorCode error = U_ZERO_ERROR;
  837. const char *name = ucnv_getStandard(i, &error);
  838. if (U_FAILURE(error)) {
  839. THROW_UFAILURE(NULL, "ucnv_getStandard", error);
  840. zend_array_destroy(Z_ARR_P(return_value));
  841. RETURN_NULL();
  842. }
  843. add_next_index_string(return_value, name);
  844. }
  845. }
  846. /* }}} */
  847. static const zend_function_entry php_converter_methods[] = {
  848. PHP_ME(UConverter, __construct, php_converter_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
  849. /* Encoding selection */
  850. PHP_ME(UConverter, setSourceEncoding, php_converter_set_encoding_arginfo, ZEND_ACC_PUBLIC)
  851. PHP_ME(UConverter, setDestinationEncoding, php_converter_set_encoding_arginfo, ZEND_ACC_PUBLIC)
  852. PHP_ME(UConverter, getSourceEncoding, php_converter_get_encoding_arginfo, ZEND_ACC_PUBLIC)
  853. PHP_ME(UConverter, getDestinationEncoding, php_converter_get_encoding_arginfo, ZEND_ACC_PUBLIC)
  854. /* Introspection for algorithmic converters */
  855. PHP_ME(UConverter, getSourceType, php_converter_get_type_arginfo, ZEND_ACC_PUBLIC)
  856. PHP_ME(UConverter, getDestinationType, php_converter_get_type_arginfo, ZEND_ACC_PUBLIC)
  857. /* Basic codeunit error handling */
  858. PHP_ME(UConverter, getSubstChars, php_converter_getSubstChars_arginfo, ZEND_ACC_PUBLIC)
  859. PHP_ME(UConverter, setSubstChars, php_converter_setSubstChars_arginfo, ZEND_ACC_PUBLIC)
  860. /* Default callback handlers */
  861. PHP_ME(UConverter, toUCallback, php_converter_toUCallback_arginfo, ZEND_ACC_PUBLIC)
  862. PHP_ME(UConverter, fromUCallback, php_converter_fromUCallback_arginfo, ZEND_ACC_PUBLIC)
  863. /* Core conversion workhorses */
  864. PHP_ME(UConverter, convert, php_converter_convert_arginfo, ZEND_ACC_PUBLIC)
  865. PHP_ME(UConverter, transcode, php_converter_transcode_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
  866. /* Error inspection */
  867. PHP_ME(UConverter, getErrorCode, php_converter_geterrorcode_arginfo, ZEND_ACC_PUBLIC)
  868. PHP_ME(UConverter, getErrorMessage, php_converter_geterrormsg_arginfo, ZEND_ACC_PUBLIC)
  869. /* Ennumeration and lookup */
  870. PHP_ME(UConverter, reasonText, php_converter_reasontext_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
  871. PHP_ME(UConverter, getAvailable, php_converter_getavailable_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
  872. PHP_ME(UConverter, getAliases, php_converter_getaliases_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
  873. PHP_ME(UConverter, getStandards, php_converter_getstandards_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
  874. PHP_FE_END
  875. };
  876. /* {{{ Converter create/clone/destroy */
  877. static void php_converter_dtor_object(zend_object *obj) {
  878. php_converter_object *objval = php_converter_fetch_object(obj);
  879. if (objval->src) {
  880. ucnv_close(objval->src);
  881. }
  882. if (objval->dest) {
  883. ucnv_close(objval->dest);
  884. }
  885. intl_error_reset(&(objval->error));
  886. }
  887. static zend_object *php_converter_object_ctor(zend_class_entry *ce, php_converter_object **pobjval) {
  888. php_converter_object *objval;
  889. objval = zend_object_alloc(sizeof(php_converter_object), ce);
  890. zend_object_std_init(&objval->obj, ce);
  891. object_properties_init(&objval->obj, ce);
  892. intl_error_init(&(objval->error));
  893. objval->obj.handlers = &php_converter_object_handlers;
  894. *pobjval = objval;
  895. return &objval->obj;
  896. }
  897. static zend_object *php_converter_create_object(zend_class_entry *ce) {
  898. php_converter_object *objval = NULL;
  899. zend_object *retval = php_converter_object_ctor(ce, &objval);
  900. object_properties_init(&(objval->obj), ce);
  901. return retval;
  902. }
  903. static zend_object *php_converter_clone_object(zval *object) {
  904. php_converter_object *objval, *oldobj = Z_INTL_CONVERTER_P(object);
  905. zend_object *retval = php_converter_object_ctor(Z_OBJCE_P(object), &objval);
  906. UErrorCode error = U_ZERO_ERROR;
  907. intl_errors_reset(&oldobj->error);
  908. objval->src = ucnv_safeClone(oldobj->src, NULL, NULL, &error);
  909. if (U_SUCCESS(error)) {
  910. error = U_ZERO_ERROR;
  911. objval->dest = ucnv_safeClone(oldobj->dest, NULL, NULL, &error);
  912. }
  913. if (U_FAILURE(error)) {
  914. zend_string *err_msg;
  915. THROW_UFAILURE(oldobj, "ucnv_safeClone", error);
  916. err_msg = intl_error_get_message(&oldobj->error);
  917. zend_throw_exception(NULL, ZSTR_VAL(err_msg), 0);
  918. zend_string_release_ex(err_msg, 0);
  919. return retval;
  920. }
  921. /* Update contexts for converter error handlers */
  922. php_converter_set_callbacks(objval, objval->src );
  923. php_converter_set_callbacks(objval, objval->dest);
  924. zend_objects_clone_members(&(objval->obj), &(oldobj->obj));
  925. /* Newly cloned object deliberately does not inherit error state from original object */
  926. return retval;
  927. }
  928. /* }}} */
  929. #define CONV_REASON_CONST(v) zend_declare_class_constant_long(php_converter_ce, "REASON_" #v, sizeof("REASON_" #v) - 1, UCNV_ ## v)
  930. #define CONV_TYPE_CONST(v) zend_declare_class_constant_long(php_converter_ce, #v , sizeof(#v) - 1, UCNV_ ## v)
  931. /* {{{ php_converter_minit */
  932. int php_converter_minit(INIT_FUNC_ARGS) {
  933. zend_class_entry ce;
  934. INIT_CLASS_ENTRY(ce, "UConverter", php_converter_methods);
  935. php_converter_ce = zend_register_internal_class(&ce);
  936. php_converter_ce->create_object = php_converter_create_object;
  937. memcpy(&php_converter_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
  938. php_converter_object_handlers.offset = XtOffsetOf(php_converter_object, obj);
  939. php_converter_object_handlers.clone_obj = php_converter_clone_object;
  940. php_converter_object_handlers.dtor_obj = php_converter_dtor_object;
  941. /* enum UConverterCallbackReason */
  942. CONV_REASON_CONST(UNASSIGNED);
  943. CONV_REASON_CONST(ILLEGAL);
  944. CONV_REASON_CONST(IRREGULAR);
  945. CONV_REASON_CONST(RESET);
  946. CONV_REASON_CONST(CLOSE);
  947. CONV_REASON_CONST(CLONE);
  948. /* enum UConverterType */
  949. CONV_TYPE_CONST(UNSUPPORTED_CONVERTER);
  950. CONV_TYPE_CONST(SBCS);
  951. CONV_TYPE_CONST(DBCS);
  952. CONV_TYPE_CONST(MBCS);
  953. CONV_TYPE_CONST(LATIN_1);
  954. CONV_TYPE_CONST(UTF8);
  955. CONV_TYPE_CONST(UTF16_BigEndian);
  956. CONV_TYPE_CONST(UTF16_LittleEndian);
  957. CONV_TYPE_CONST(UTF32_BigEndian);
  958. CONV_TYPE_CONST(UTF32_LittleEndian);
  959. CONV_TYPE_CONST(EBCDIC_STATEFUL);
  960. CONV_TYPE_CONST(ISO_2022);
  961. CONV_TYPE_CONST(LMBCS_1);
  962. CONV_TYPE_CONST(LMBCS_2);
  963. CONV_TYPE_CONST(LMBCS_3);
  964. CONV_TYPE_CONST(LMBCS_4);
  965. CONV_TYPE_CONST(LMBCS_5);
  966. CONV_TYPE_CONST(LMBCS_6);
  967. CONV_TYPE_CONST(LMBCS_8);
  968. CONV_TYPE_CONST(LMBCS_11);
  969. CONV_TYPE_CONST(LMBCS_16);
  970. CONV_TYPE_CONST(LMBCS_17);
  971. CONV_TYPE_CONST(LMBCS_18);
  972. CONV_TYPE_CONST(LMBCS_19);
  973. CONV_TYPE_CONST(LMBCS_LAST);
  974. CONV_TYPE_CONST(HZ);
  975. CONV_TYPE_CONST(SCSU);
  976. CONV_TYPE_CONST(ISCII);
  977. CONV_TYPE_CONST(US_ASCII);
  978. CONV_TYPE_CONST(UTF7);
  979. CONV_TYPE_CONST(BOCU1);
  980. CONV_TYPE_CONST(UTF16);
  981. CONV_TYPE_CONST(UTF32);
  982. CONV_TYPE_CONST(CESU8);
  983. CONV_TYPE_CONST(IMAP_MAILBOX);
  984. return SUCCESS;
  985. }
  986. /* }}} */
  987. /*
  988. * Local variables:
  989. * tab-width: 4
  990. * c-basic-offset: 4
  991. * End:
  992. * vim600: noet sw=4 ts=4 fdm=marker
  993. * vim<600: noet sw=4 ts=4
  994. */