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