root/ext/intl/converter/converter.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. php_converter_throw_failure
  2. php_converter_default_callback
  3. ZEND_BEGIN_ARG_INFO_EX
  4. ZEND_BEGIN_ARG_INFO_EX
  5. php_converter_check_limits
  6. php_converter_append_toUnicode_target
  7. php_converter_to_u_callback
  8. php_converter_append_fromUnicode_target
  9. php_converter_from_u_callback
  10. php_converter_set_callbacks
  11. php_converter_set_encoding
  12. ZEND_BEGIN_ARG_INFO_EX
  13. PHP_METHOD
  14. PHP_METHOD
  15. ZEND_BEGIN_ARG_INFO_EX
  16. PHP_METHOD
  17. PHP_METHOD
  18. ZEND_BEGIN_ARG_INFO_EX
  19. PHP_METHOD
  20. PHP_METHOD
  21. php_converter_resolve_callback
  22. ZEND_BEGIN_ARG_INFO_EX
  23. ZEND_BEGIN_ARG_INFO_EX
  24. ZEND_BEGIN_ARG_INFO_EX
  25. php_converter_do_convert
  26. ZEND_BEGIN_ARG_INFO_EX
  27. ZEND_BEGIN_ARG_INFO_EX
  28. ZEND_BEGIN_ARG_INFO_EX
  29. ZEND_BEGIN_ARG_INFO_EX
  30. ZEND_BEGIN_ARG_INFO_EX
  31. ZEND_BEGIN_ARG_INFO_EX
  32. ZEND_BEGIN_ARG_INFO_EX
  33. ZEND_BEGIN_ARG_INFO_EX
  34. php_converter_free_object
  35. php_converter_object_ctor
  36. php_converter_create_object
  37. php_converter_clone_object
  38. php_converter_minit

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

/* [<][>][^][v][top][bottom][index][help] */