root/ext/intl/converter/converter.c

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

DEFINITIONS

This source file includes following definitions.
  1. php_converter_fetch_object
  2. php_converter_throw_failure
  3. php_converter_default_callback
  4. ZEND_BEGIN_ARG_INFO_EX
  5. ZEND_BEGIN_ARG_INFO_EX
  6. php_converter_check_limits
  7. php_converter_append_toUnicode_target
  8. php_converter_to_u_callback
  9. php_converter_append_fromUnicode_target
  10. php_converter_from_u_callback
  11. php_converter_set_callbacks
  12. php_converter_set_encoding
  13. ZEND_BEGIN_ARG_INFO_EX
  14. PHP_METHOD
  15. PHP_METHOD
  16. ZEND_BEGIN_ARG_INFO_EX
  17. PHP_METHOD
  18. PHP_METHOD
  19. ZEND_BEGIN_ARG_INFO_EX
  20. PHP_METHOD
  21. PHP_METHOD
  22. php_converter_resolve_callback
  23. ZEND_BEGIN_ARG_INFO_EX
  24. ZEND_BEGIN_ARG_INFO_EX
  25. ZEND_BEGIN_ARG_INFO_EX
  26. php_converter_do_convert
  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. ZEND_BEGIN_ARG_INFO_EX
  35. php_converter_dtor_object
  36. php_converter_object_ctor
  37. php_converter_create_object
  38. php_converter_clone_object
  39. php_converter_minit

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

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