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