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
27typedef 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
36static 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
41static zend_class_entry     *php_converter_ce;
42static 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 */
49static 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 */
63static 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) */
111ZEND_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)
116ZEND_END_ARG_INFO();
117static 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) */
133ZEND_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)
138ZEND_END_ARG_INFO();
139static 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 */
153static 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 */
165static 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 */
222static 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 */
262static 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 */
297static 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 */
344static 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 */
374static 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 */
411ZEND_BEGIN_ARG_INFO_EX(php_converter_set_encoding_arginfo, 0, ZEND_RETURN_VALUE, 1)
412    ZEND_ARG_INFO(0, encoding)
413ZEND_END_ARG_INFO();
414static 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) */
431static 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) */
438static 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 */
445ZEND_BEGIN_ARG_INFO_EX(php_converter_get_encoding_arginfo, 0, ZEND_RETURN_VALUE, 0)
446ZEND_END_ARG_INFO();
447static 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() */
472static 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() */
479static 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 */
486ZEND_BEGIN_ARG_INFO_EX(php_converter_get_type_arginfo, 0, ZEND_RETURN_VALUE, 0)
487ZEND_END_ARG_INFO();
488static 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() */
512static 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() */
519static 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 */
526static 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']]) */
549ZEND_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)
552ZEND_END_ARG_INFO();
553
554static 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) */
575ZEND_BEGIN_ARG_INFO_EX(php_converter_setSubstChars_arginfo, 0, ZEND_RETURN_VALUE, 1)
576    ZEND_ARG_INFO(0, chars)
577ZEND_END_ARG_INFO();
578
579static 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() */
621ZEND_BEGIN_ARG_INFO_EX(php_converter_getSubstChars_arginfo, 0, ZEND_RETURN_VALUE, 0)
622ZEND_END_ARG_INFO();
623
624static 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 */
655static zend_bool php_converter_do_convert(UConverter *dest_cnv, char **pdest, int32_t *pdest_len,
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     dest_len,
661                temp_len;
662    char        *dest;
663    UChar       *temp;
664
665    if (!src_cnv || !dest_cnv) {
666        php_converter_throw_failure(objval, U_INVALID_STATE_ERROR,
667                                    "Internal converters not initialized");
668        return 0;
669    }
670
671    /* Get necessary buffer size first */
672    temp_len = 1 + ucnv_toUChars(src_cnv, NULL, 0, src, src_len, &error);
673    if (U_FAILURE(error) && error != U_BUFFER_OVERFLOW_ERROR) {
674        THROW_UFAILURE(objval, "ucnv_toUChars", error);
675        return 0;
676    }
677    temp = safe_emalloc(sizeof(UChar), temp_len, sizeof(UChar));
678
679    /* Convert to intermediate UChar* array */
680    error = U_ZERO_ERROR;
681    temp_len = ucnv_toUChars(src_cnv, temp, temp_len, src, src_len, &error);
682    if (U_FAILURE(error)) {
683        THROW_UFAILURE(objval, "ucnv_toUChars", error);
684        efree(temp);
685        return 0;
686    }
687    temp[temp_len] = 0;
688
689    /* Get necessary output buffer size */
690    dest_len = 1 + ucnv_fromUChars(dest_cnv, NULL, 0, temp, temp_len, &error);
691    if (U_FAILURE(error) && error != U_BUFFER_OVERFLOW_ERROR) {
692        THROW_UFAILURE(objval, "ucnv_fromUChars", error);
693        efree(temp);
694        return 0;
695    }
696
697    dest = safe_emalloc(sizeof(char), dest_len, sizeof(char));
698
699    /* Convert to final encoding */
700    error = U_ZERO_ERROR;
701    dest_len = ucnv_fromUChars(dest_cnv, dest, dest_len, temp, temp_len, &error);
702    efree(temp);
703    if (U_FAILURE(error)) {
704        THROW_UFAILURE(objval, "ucnv_fromUChars", error);
705        efree(dest);
706        return 0;
707    }
708
709    *pdest = dest;
710    if (pdest_len) {
711        *pdest_len = dest_len;
712    }
713
714    return 1;
715}
716/* }}} */
717
718/* {{{ proto string UConverter::reasonText(long reason) */
719#define UCNV_REASON_CASE(v) case (UCNV_ ## v) : RETURN_STRINGL( "REASON_" #v , sizeof( "REASON_" #v ) - 1);
720ZEND_BEGIN_ARG_INFO_EX(php_converter_reasontext_arginfo, 0, ZEND_RETURN_VALUE, 0)
721    ZEND_ARG_INFO(0, reason)
722ZEND_END_ARG_INFO();
723static PHP_METHOD(UConverter, reasonText) {
724    zend_long reason;
725
726    if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &reason) == FAILURE) {
727        intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
728            "UConverter::reasonText(): bad arguments", 0);
729        RETURN_FALSE;
730    }
731    intl_error_reset(NULL);
732
733    switch (reason) {
734        UCNV_REASON_CASE(UNASSIGNED)
735        UCNV_REASON_CASE(ILLEGAL)
736        UCNV_REASON_CASE(IRREGULAR)
737        UCNV_REASON_CASE(RESET)
738        UCNV_REASON_CASE(CLOSE)
739        UCNV_REASON_CASE(CLONE)
740        default:
741            php_error_docref(NULL, E_WARNING, "Unknown UConverterCallbackReason: %pd", reason);
742            RETURN_FALSE;
743    }
744}
745/* }}} */
746
747/* {{{ proto string UConverter::convert(string str[, bool reverse]) */
748ZEND_BEGIN_ARG_INFO_EX(php_converter_convert_arginfo, 0, ZEND_RETURN_VALUE, 1)
749        ZEND_ARG_INFO(0, str)
750    ZEND_ARG_INFO(0, reverse)
751ZEND_END_ARG_INFO();
752
753static PHP_METHOD(UConverter, convert) {
754        php_converter_object *objval = CONV_GET(getThis());
755    char *str, *dest;
756    size_t str_len;
757    int32_t dest_len;
758    zend_bool reverse = 0;
759
760    if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|b",
761                              &str, &str_len, &reverse) == FAILURE) {
762        intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
763            "UConverter::convert(): bad arguments", 0);
764        RETURN_FALSE;
765    }
766    intl_errors_reset(&objval->error);
767
768    if (php_converter_do_convert(reverse ? objval->src : objval->dest,
769                                 &dest, &dest_len,
770                                 reverse ? objval->dest : objval->src,
771                                 str,   str_len,
772                                 objval)) {
773        RETVAL_STRINGL(dest, dest_len);
774        //???
775        efree(dest);
776        return;
777    } else {
778        RETURN_FALSE;
779    }
780}
781/* }}} */
782
783/* {{{ proto string UConverter::transcode(string $str, string $toEncoding, string $fromEncoding[, Array $options = array()]) */
784ZEND_BEGIN_ARG_INFO_EX(php_converter_transcode_arginfo, 0, ZEND_RETURN_VALUE, 3)
785    ZEND_ARG_INFO(0, str)
786    ZEND_ARG_INFO(0, toEncoding)
787    ZEND_ARG_INFO(0, fromEncoding)
788    ZEND_ARG_ARRAY_INFO(0, options, 1)
789ZEND_END_ARG_INFO();
790
791static PHP_METHOD(UConverter, transcode) {
792    char *str, *src, *dest;
793    size_t str_len, src_len, dest_len;
794    zval *options = NULL;
795    UConverter *src_cnv = NULL, *dest_cnv = NULL;
796
797    if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss|a!",
798            &str, &str_len, &dest, &dest_len, &src, &src_len, &options) == FAILURE) {
799        intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
800            "UConverter::transcode(): bad arguments", 0);
801        RETURN_FALSE;
802    }
803    intl_error_reset(NULL);
804
805    if (php_converter_set_encoding(NULL, &src_cnv,  src,  src_len) &&
806        php_converter_set_encoding(NULL, &dest_cnv, dest, dest_len)) {
807        char *out = NULL;
808        int out_len = 0;
809        UErrorCode error = U_ZERO_ERROR;
810
811        if (options && zend_hash_num_elements(Z_ARRVAL_P(options))) {
812            zval *tmpzval;
813
814            if (U_SUCCESS(error) &&
815                (tmpzval = zend_hash_str_find(Z_ARRVAL_P(options), "from_subst", sizeof("from_subst") - 1)) != NULL &&
816                Z_TYPE_P(tmpzval) == IS_STRING) {
817                error = U_ZERO_ERROR;
818                ucnv_setSubstChars(src_cnv, Z_STRVAL_P(tmpzval), Z_STRLEN_P(tmpzval) & 0x7F, &error);
819            }
820            if (U_SUCCESS(error) &&
821                (tmpzval = zend_hash_str_find(Z_ARRVAL_P(options), "to_subst", sizeof("to_subst") - 1)) != NULL &&
822                Z_TYPE_P(tmpzval) == IS_STRING) {
823                error = U_ZERO_ERROR;
824                ucnv_setSubstChars(dest_cnv, Z_STRVAL_P(tmpzval), Z_STRLEN_P(tmpzval) & 0x7F, &error);
825            }
826        }
827
828        if (U_SUCCESS(error) &&
829            php_converter_do_convert(dest_cnv, &out, &out_len, src_cnv, str, str_len, NULL)) {
830            RETVAL_STRINGL(out, out_len);
831            //???
832            efree(out);
833            return;
834        }
835
836        if (U_FAILURE(error)) {
837            THROW_UFAILURE(NULL, "transcode", error);
838            RETVAL_FALSE;
839        }
840    } else {
841        RETVAL_FALSE;
842    }
843
844    if (src_cnv) {
845        ucnv_close(src_cnv);
846    }
847    if (dest_cnv) {
848        ucnv_close(dest_cnv);
849    }
850}
851/* }}} */
852
853/* {{{ proto int UConverter::getErrorCode() */
854ZEND_BEGIN_ARG_INFO_EX(php_converter_geterrorcode_arginfo, 0, ZEND_RETURN_VALUE, 0)
855ZEND_END_ARG_INFO();
856static PHP_METHOD(UConverter, getErrorCode) {
857    php_converter_object *objval = CONV_GET(getThis());
858
859    if (zend_parse_parameters_none() == FAILURE) {
860        intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
861            "UConverter::getErrorCode(): expected no arguments", 0);
862        RETURN_FALSE;
863    }
864
865    RETURN_LONG(intl_error_get_code(&(objval->error)));
866}
867/* }}} */
868
869/* {{{ proto string UConverter::getErrorMessage() */
870ZEND_BEGIN_ARG_INFO_EX(php_converter_geterrormsg_arginfo, 0, ZEND_RETURN_VALUE, 0)
871ZEND_END_ARG_INFO();
872static PHP_METHOD(UConverter, getErrorMessage) {
873    php_converter_object *objval = CONV_GET(getThis());
874    zend_string *message = intl_error_get_message(&(objval->error));
875
876    if (zend_parse_parameters_none() == FAILURE) {
877        intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
878            "UConverter::getErrorMessage(): expected no arguments", 0);
879        RETURN_FALSE;
880    }
881
882    if (message) {
883        RETURN_STR(message);
884    } else {
885        RETURN_NULL();
886    }
887}
888/* }}} */
889
890/* {{{ proto array UConverter::getAvailable() */
891ZEND_BEGIN_ARG_INFO_EX(php_converter_getavailable_arginfo, 0, ZEND_RETURN_VALUE, 0)
892ZEND_END_ARG_INFO();
893static PHP_METHOD(UConverter, getAvailable) {
894    int32_t i,
895            count = ucnv_countAvailable();
896
897    if (zend_parse_parameters_none() == FAILURE) {
898        intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
899            "UConverter::getErrorMessage(): expected no arguments", 0);
900        RETURN_FALSE;
901    }
902    intl_error_reset(NULL);
903
904    array_init(return_value);
905    for(i = 0; i < count; i++) {
906        const char *name = ucnv_getAvailableName(i);
907        add_next_index_string(return_value, name);
908    }
909}
910/* }}} */
911
912/* {{{ proto array UConverter::getAliases(string name) */
913ZEND_BEGIN_ARG_INFO_EX(php_converter_getaliases_arginfo, 0, ZEND_RETURN_VALUE, 0)
914    ZEND_ARG_INFO(0, name)
915ZEND_END_ARG_INFO();
916static PHP_METHOD(UConverter, getAliases) {
917    char *name;
918    size_t name_len;
919    UErrorCode error = U_ZERO_ERROR;
920    uint16_t i, count;
921
922    if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
923        intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
924            "UConverter::getAliases(): bad arguments", 0);
925        RETURN_FALSE;
926    }
927    intl_error_reset(NULL);
928
929    count = ucnv_countAliases(name, &error);
930    if (U_FAILURE(error)) {
931        THROW_UFAILURE(NULL, "ucnv_countAliases", error);
932        RETURN_FALSE;
933    }
934
935    array_init(return_value);
936    for(i = 0; i < count; i++) {
937        const char *alias;
938
939        error = U_ZERO_ERROR;
940        alias = ucnv_getAlias(name, i, &error);
941        if (U_FAILURE(error)) {
942            THROW_UFAILURE(NULL, "ucnv_getAlias", error);
943            zval_dtor(return_value);
944            RETURN_NULL();
945        }
946        add_next_index_string(return_value, alias);
947    }
948}
949/* }}} */
950
951/* {{{ proto array UConverter::getStandards() */
952ZEND_BEGIN_ARG_INFO_EX(php_converter_getstandards_arginfo, 0, ZEND_RETURN_VALUE, 0)
953ZEND_END_ARG_INFO();
954static PHP_METHOD(UConverter, getStandards) {
955    uint16_t i, count;
956
957    if (zend_parse_parameters_none() == FAILURE) {
958        intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
959            "UConverter::getStandards(): expected no arguments", 0);
960        RETURN_FALSE;
961    }
962    intl_error_reset(NULL);
963
964    array_init(return_value);
965    count = ucnv_countStandards();
966    for(i = 0; i < count; i++) {
967        UErrorCode error = U_ZERO_ERROR;
968        const char *name = ucnv_getStandard(i, &error);
969        if (U_FAILURE(error)) {
970            THROW_UFAILURE(NULL, "ucnv_getStandard", error);
971            zval_dtor(return_value);
972            RETURN_NULL();
973        }
974        add_next_index_string(return_value, name);
975    }
976}
977/* }}} */
978
979static zend_function_entry php_converter_methods[] = {
980    PHP_ME(UConverter, __construct,            php_converter_arginfo,                   ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
981
982    /* Encoding selection */
983    PHP_ME(UConverter, setSourceEncoding,      php_converter_set_encoding_arginfo,      ZEND_ACC_PUBLIC)
984    PHP_ME(UConverter, setDestinationEncoding, php_converter_set_encoding_arginfo,      ZEND_ACC_PUBLIC)
985    PHP_ME(UConverter, getSourceEncoding,      php_converter_get_encoding_arginfo,      ZEND_ACC_PUBLIC)
986    PHP_ME(UConverter, getDestinationEncoding, php_converter_get_encoding_arginfo,      ZEND_ACC_PUBLIC)
987
988    /* Introspection for algorithmic converters */
989    PHP_ME(UConverter, getSourceType,          php_converter_get_type_arginfo,          ZEND_ACC_PUBLIC)
990    PHP_ME(UConverter, getDestinationType,     php_converter_get_type_arginfo,          ZEND_ACC_PUBLIC)
991
992    /* Basic codeunit error handling */
993    PHP_ME(UConverter, getSubstChars,          php_converter_getSubstChars_arginfo,     ZEND_ACC_PUBLIC)
994    PHP_ME(UConverter, setSubstChars,          php_converter_setSubstChars_arginfo,     ZEND_ACC_PUBLIC)
995
996    /* Default callback handlers */
997    PHP_ME(UConverter, toUCallback,            php_converter_toUCallback_arginfo,       ZEND_ACC_PUBLIC)
998    PHP_ME(UConverter, fromUCallback,          php_converter_fromUCallback_arginfo,     ZEND_ACC_PUBLIC)
999
1000    /* Core conversion workhorses */
1001    PHP_ME(UConverter, convert,                php_converter_convert_arginfo,           ZEND_ACC_PUBLIC)
1002    PHP_ME(UConverter, transcode,              php_converter_transcode_arginfo,         ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
1003
1004    /* Error inspection */
1005    PHP_ME(UConverter, getErrorCode,           php_converter_geterrorcode_arginfo,      ZEND_ACC_PUBLIC)
1006    PHP_ME(UConverter, getErrorMessage,        php_converter_geterrormsg_arginfo,       ZEND_ACC_PUBLIC)
1007
1008    /* Ennumeration and lookup */
1009    PHP_ME(UConverter, reasonText,             php_converter_reasontext_arginfo,        ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
1010    PHP_ME(UConverter, getAvailable,           php_converter_getavailable_arginfo,      ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
1011    PHP_ME(UConverter, getAliases,             php_converter_getaliases_arginfo,        ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
1012    PHP_ME(UConverter, getStandards,           php_converter_getstandards_arginfo,      ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
1013    { NULL, NULL, NULL }
1014};
1015
1016/* {{{ Converter create/clone/destroy */
1017static void php_converter_dtor_object(zend_object *obj) {
1018    php_converter_object *objval = php_converter_fetch_object(obj);
1019
1020    if (objval->src) {
1021        ucnv_close(objval->src);
1022    }
1023
1024    if (objval->dest) {
1025        ucnv_close(objval->dest);
1026    }
1027
1028    intl_error_reset(&(objval->error));
1029}
1030
1031static zend_object *php_converter_object_ctor(zend_class_entry *ce, php_converter_object **pobjval) {
1032    php_converter_object *objval;
1033
1034    objval = ecalloc(1, sizeof(php_converter_object) + zend_object_properties_size(ce));
1035
1036    zend_object_std_init(&objval->obj, ce );
1037    intl_error_init(&(objval->error));
1038
1039    objval->obj.handlers = &php_converter_object_handlers;
1040    *pobjval = objval;
1041
1042    return &objval->obj;
1043}
1044
1045static zend_object *php_converter_create_object(zend_class_entry *ce) {
1046    php_converter_object *objval = NULL;
1047    zend_object *retval = php_converter_object_ctor(ce, &objval);
1048
1049    object_properties_init(&(objval->obj), ce);
1050
1051    return retval;
1052}
1053
1054static zend_object *php_converter_clone_object(zval *object) {
1055    php_converter_object *objval, *oldobj = Z_INTL_CONVERTER_P(object);
1056    zend_object *retval = php_converter_object_ctor(Z_OBJCE_P(object), &objval);
1057    UErrorCode error = U_ZERO_ERROR;
1058
1059    intl_errors_reset(&oldobj->error);
1060
1061    objval->src = ucnv_safeClone(oldobj->src, NULL, NULL, &error);
1062    if (U_SUCCESS(error)) {
1063        error = U_ZERO_ERROR;
1064        objval->dest = ucnv_safeClone(oldobj->dest, NULL, NULL, &error);
1065    }
1066    if (U_FAILURE(error)) {
1067        zend_string *err_msg;
1068        THROW_UFAILURE(oldobj, "ucnv_safeClone", error);
1069
1070        err_msg = intl_error_get_message(&oldobj->error);
1071        zend_throw_exception(NULL, err_msg->val, 0);
1072        zend_string_release(err_msg);
1073
1074        return retval;
1075    }
1076
1077    /* Update contexts for converter error handlers */
1078    php_converter_set_callbacks(objval, objval->src );
1079    php_converter_set_callbacks(objval, objval->dest);
1080
1081    zend_objects_clone_members(&(objval->obj), &(oldobj->obj));
1082
1083    /* Newly cloned object deliberately does not inherit error state from original object */
1084
1085    return retval;
1086}
1087/* }}} */
1088
1089#define CONV_REASON_CONST(v) zend_declare_class_constant_long(php_converter_ce, "REASON_" #v, sizeof("REASON_" #v) - 1, UCNV_ ## v)
1090#define CONV_TYPE_CONST(v)   zend_declare_class_constant_long(php_converter_ce, #v ,          sizeof(#v) - 1,           UCNV_ ## v)
1091
1092/* {{{ php_converter_minit */
1093int php_converter_minit(INIT_FUNC_ARGS) {
1094    zend_class_entry ce;
1095
1096    INIT_CLASS_ENTRY(ce, "UConverter", php_converter_methods);
1097    php_converter_ce = zend_register_internal_class(&ce);
1098    php_converter_ce->create_object = php_converter_create_object;
1099    memcpy(&php_converter_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1100    php_converter_object_handlers.offset = XtOffsetOf(php_converter_object, obj);
1101    php_converter_object_handlers.clone_obj = php_converter_clone_object;
1102    php_converter_object_handlers.dtor_obj = php_converter_dtor_object;
1103
1104    /* enum UConverterCallbackReason */
1105    CONV_REASON_CONST(UNASSIGNED);
1106    CONV_REASON_CONST(ILLEGAL);
1107    CONV_REASON_CONST(IRREGULAR);
1108    CONV_REASON_CONST(RESET);
1109    CONV_REASON_CONST(CLOSE);
1110    CONV_REASON_CONST(CLONE);
1111
1112    /* enum UConverterType */
1113    CONV_TYPE_CONST(UNSUPPORTED_CONVERTER);
1114    CONV_TYPE_CONST(SBCS);
1115    CONV_TYPE_CONST(DBCS);
1116    CONV_TYPE_CONST(MBCS);
1117    CONV_TYPE_CONST(LATIN_1);
1118    CONV_TYPE_CONST(UTF8);
1119    CONV_TYPE_CONST(UTF16_BigEndian);
1120    CONV_TYPE_CONST(UTF16_LittleEndian);
1121    CONV_TYPE_CONST(UTF32_BigEndian);
1122    CONV_TYPE_CONST(UTF32_LittleEndian);
1123    CONV_TYPE_CONST(EBCDIC_STATEFUL);
1124    CONV_TYPE_CONST(ISO_2022);
1125    CONV_TYPE_CONST(LMBCS_1);
1126    CONV_TYPE_CONST(LMBCS_2);
1127    CONV_TYPE_CONST(LMBCS_3);
1128    CONV_TYPE_CONST(LMBCS_4);
1129    CONV_TYPE_CONST(LMBCS_5);
1130    CONV_TYPE_CONST(LMBCS_6);
1131    CONV_TYPE_CONST(LMBCS_8);
1132    CONV_TYPE_CONST(LMBCS_11);
1133    CONV_TYPE_CONST(LMBCS_16);
1134    CONV_TYPE_CONST(LMBCS_17);
1135    CONV_TYPE_CONST(LMBCS_18);
1136    CONV_TYPE_CONST(LMBCS_19);
1137    CONV_TYPE_CONST(LMBCS_LAST);
1138    CONV_TYPE_CONST(HZ);
1139    CONV_TYPE_CONST(SCSU);
1140    CONV_TYPE_CONST(ISCII);
1141    CONV_TYPE_CONST(US_ASCII);
1142    CONV_TYPE_CONST(UTF7);
1143    CONV_TYPE_CONST(BOCU1);
1144    CONV_TYPE_CONST(UTF16);
1145    CONV_TYPE_CONST(UTF32);
1146    CONV_TYPE_CONST(CESU8);
1147    CONV_TYPE_CONST(IMAP_MAILBOX);
1148
1149    return SUCCESS;
1150}
1151/* }}} */
1152
1153/*
1154 * Local variables:
1155 * tab-width: 4
1156 * c-basic-offset: 4
1157 * End:
1158 * vim600: noet sw=4 ts=4 fdm=marker
1159 * vim<600: noet sw=4 ts=4
1160 */
1161