converter.c 38 KB

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