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