Annotation of embedaddon/php/ext/iconv/iconv.c, revision 1.1

1.1     ! misho       1: /*
        !             2:    +----------------------------------------------------------------------+
        !             3:    | PHP Version 5                                                        |
        !             4:    +----------------------------------------------------------------------+
        !             5:    | Copyright (c) 1997-2012 The PHP Group                                |
        !             6:    +----------------------------------------------------------------------+
        !             7:    | This source file is subject to version 3.01 of the PHP license,      |
        !             8:    | that is bundled with this package in the file LICENSE, and is        |
        !             9:    | available through the world-wide-web at the following url:           |
        !            10:    | http://www.php.net/license/3_01.txt                                  |
        !            11:    | If you did not receive a copy of the PHP license and are unable to   |
        !            12:    | obtain it through the world-wide-web, please send a note to          |
        !            13:    | license@php.net so we can mail you a copy immediately.               |
        !            14:    +----------------------------------------------------------------------+
        !            15:    | Authors: Rui Hirokawa <rui_hirokawa@ybb.ne.jp>                       |
        !            16:    |          Stig Bakken <ssb@php.net>                                   |
        !            17:    |          Moriyoshi Koizumi <moriyoshi@php.net>                       |
        !            18:    +----------------------------------------------------------------------+
        !            19:  */
        !            20: 
        !            21: /* $Id: iconv.c 321634 2012-01-01 13:15:04Z felipe $ */
        !            22: 
        !            23: #ifdef HAVE_CONFIG_H
        !            24: #include "config.h"
        !            25: #endif
        !            26: 
        !            27: #include "php.h"
        !            28: #include "php_globals.h"
        !            29: #include "ext/standard/info.h"
        !            30: #include "main/php_output.h"
        !            31: #include "SAPI.h"
        !            32: #include "php_ini.h"
        !            33: 
        !            34: #ifdef HAVE_STDLIB_H
        !            35: # include <stdlib.h>
        !            36: #endif
        !            37: 
        !            38: #include <errno.h>
        !            39: 
        !            40: #include "php_iconv.h"
        !            41: 
        !            42: #ifdef HAVE_ICONV
        !            43: 
        !            44: #ifdef PHP_ICONV_H_PATH
        !            45: #include PHP_ICONV_H_PATH
        !            46: #else
        !            47: #include <iconv.h>
        !            48: #endif
        !            49: 
        !            50: #ifdef HAVE_GLIBC_ICONV
        !            51: #include <gnu/libc-version.h>
        !            52: #endif
        !            53: 
        !            54: #ifdef HAVE_LIBICONV
        !            55: #undef iconv
        !            56: #endif
        !            57: 
        !            58: #include "ext/standard/php_smart_str.h"
        !            59: #include "ext/standard/base64.h"
        !            60: #include "ext/standard/quot_print.h"
        !            61: 
        !            62: #define _php_iconv_memequal(a, b, c) \
        !            63:   ((c) == sizeof(unsigned long) ? *((unsigned long *)(a)) == *((unsigned long *)(b)) : ((c) == sizeof(unsigned int) ? *((unsigned int *)(a)) == *((unsigned int *)(b)) : memcmp(a, b, c) == 0))
        !            64: 
        !            65: /* {{{ arginfo */
        !            66: ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_strlen, 0, 0, 1)
        !            67:        ZEND_ARG_INFO(0, str)
        !            68:        ZEND_ARG_INFO(0, charset)
        !            69: ZEND_END_ARG_INFO()
        !            70: 
        !            71: ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_substr, 0, 0, 2)
        !            72:        ZEND_ARG_INFO(0, str)
        !            73:        ZEND_ARG_INFO(0, offset)
        !            74:        ZEND_ARG_INFO(0, length)
        !            75:        ZEND_ARG_INFO(0, charset)
        !            76: ZEND_END_ARG_INFO()
        !            77: 
        !            78: ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_strpos, 0, 0, 2)
        !            79:        ZEND_ARG_INFO(0, haystack)
        !            80:        ZEND_ARG_INFO(0, needle)
        !            81:        ZEND_ARG_INFO(0, offset)
        !            82:        ZEND_ARG_INFO(0, charset)
        !            83: ZEND_END_ARG_INFO()
        !            84: 
        !            85: ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_strrpos, 0, 0, 2)
        !            86:        ZEND_ARG_INFO(0, haystack)
        !            87:        ZEND_ARG_INFO(0, needle)
        !            88:        ZEND_ARG_INFO(0, charset)
        !            89: ZEND_END_ARG_INFO()
        !            90: 
        !            91: ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_mime_encode, 0, 0, 2)
        !            92:        ZEND_ARG_INFO(0, field_name)
        !            93:        ZEND_ARG_INFO(0, field_value)
        !            94:        ZEND_ARG_INFO(0, preference) /* ZEND_ARG_ARRAY_INFO(0, preference, 1) */
        !            95: ZEND_END_ARG_INFO()
        !            96: 
        !            97: ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_mime_decode, 0, 0, 1)
        !            98:        ZEND_ARG_INFO(0, encoded_string)
        !            99:        ZEND_ARG_INFO(0, mode)
        !           100:        ZEND_ARG_INFO(0, charset)
        !           101: ZEND_END_ARG_INFO()
        !           102: 
        !           103: ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_mime_decode_headers, 0, 0, 1)
        !           104:        ZEND_ARG_INFO(0, headers)
        !           105:        ZEND_ARG_INFO(0, mode)
        !           106:        ZEND_ARG_INFO(0, charset)
        !           107: ZEND_END_ARG_INFO()
        !           108: 
        !           109: ZEND_BEGIN_ARG_INFO(arginfo_iconv, 0)
        !           110:        ZEND_ARG_INFO(0, in_charset)
        !           111:        ZEND_ARG_INFO(0, out_charset)
        !           112:        ZEND_ARG_INFO(0, str)
        !           113: ZEND_END_ARG_INFO()
        !           114: 
        !           115: ZEND_BEGIN_ARG_INFO(arginfo_ob_iconv_handler, 0)
        !           116:        ZEND_ARG_INFO(0, contents)
        !           117:        ZEND_ARG_INFO(0, status)
        !           118: ZEND_END_ARG_INFO()
        !           119: 
        !           120: ZEND_BEGIN_ARG_INFO(arginfo_iconv_set_encoding, 0)
        !           121:        ZEND_ARG_INFO(0, type)
        !           122:        ZEND_ARG_INFO(0, charset)
        !           123: ZEND_END_ARG_INFO()
        !           124: 
        !           125: ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_get_encoding, 0, 0, 0)
        !           126:        ZEND_ARG_INFO(0, type)
        !           127: ZEND_END_ARG_INFO()
        !           128: 
        !           129: /* }}} */
        !           130: 
        !           131: /* {{{ iconv_functions[]
        !           132:  */
        !           133: const zend_function_entry iconv_functions[] = {
        !           134:        PHP_RAW_NAMED_FE(iconv,php_if_iconv,                            arginfo_iconv)
        !           135:        PHP_FE(ob_iconv_handler,                                                arginfo_ob_iconv_handler)
        !           136:        PHP_FE(iconv_get_encoding,                                              arginfo_iconv_get_encoding)
        !           137:        PHP_FE(iconv_set_encoding,                                              arginfo_iconv_set_encoding)
        !           138:        PHP_FE(iconv_strlen,                                                    arginfo_iconv_strlen)
        !           139:        PHP_FE(iconv_substr,                                                    arginfo_iconv_substr)
        !           140:        PHP_FE(iconv_strpos,                                                    arginfo_iconv_strpos)
        !           141:        PHP_FE(iconv_strrpos,                                                   arginfo_iconv_strrpos)
        !           142:        PHP_FE(iconv_mime_encode,                                               arginfo_iconv_mime_encode)
        !           143:        PHP_FE(iconv_mime_decode,                                               arginfo_iconv_mime_decode)
        !           144:        PHP_FE(iconv_mime_decode_headers,                               arginfo_iconv_mime_decode_headers)
        !           145:        PHP_FE_END
        !           146: };
        !           147: /* }}} */
        !           148: 
        !           149: ZEND_DECLARE_MODULE_GLOBALS(iconv)
        !           150: static PHP_GINIT_FUNCTION(iconv);
        !           151: 
        !           152: /* {{{ iconv_module_entry
        !           153:  */
        !           154: zend_module_entry iconv_module_entry = {
        !           155:        STANDARD_MODULE_HEADER,
        !           156:        "iconv",
        !           157:        iconv_functions,
        !           158:        PHP_MINIT(miconv),
        !           159:        PHP_MSHUTDOWN(miconv),
        !           160:        NULL,
        !           161:        NULL,
        !           162:        PHP_MINFO(miconv),
        !           163:        NO_VERSION_YET,
        !           164:        PHP_MODULE_GLOBALS(iconv),
        !           165:        PHP_GINIT(iconv),
        !           166:        NULL,
        !           167:        NULL,
        !           168:        STANDARD_MODULE_PROPERTIES_EX
        !           169: };
        !           170: /* }}} */
        !           171: 
        !           172: #ifdef COMPILE_DL_ICONV
        !           173: ZEND_GET_MODULE(iconv)
        !           174: #endif
        !           175: 
        !           176: /* {{{ PHP_GINIT_FUNCTION */
        !           177: static PHP_GINIT_FUNCTION(iconv)
        !           178: {
        !           179:        iconv_globals->input_encoding = NULL;
        !           180:        iconv_globals->output_encoding = NULL;
        !           181:        iconv_globals->internal_encoding = NULL;
        !           182: }
        !           183: /* }}} */
        !           184: 
        !           185: #if defined(HAVE_LIBICONV) && defined(ICONV_ALIASED_LIBICONV)
        !           186: #define iconv libiconv
        !           187: #endif
        !           188: 
        !           189: /* {{{ typedef enum php_iconv_enc_scheme_t */
        !           190: typedef enum _php_iconv_enc_scheme_t {
        !           191:        PHP_ICONV_ENC_SCHEME_BASE64,
        !           192:        PHP_ICONV_ENC_SCHEME_QPRINT
        !           193: } php_iconv_enc_scheme_t;
        !           194: /* }}} */
        !           195: 
        !           196: #define PHP_ICONV_MIME_DECODE_STRICT            (1<<0)
        !           197: #define PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR (1<<1)
        !           198: 
        !           199: /* {{{ prototypes */ 
        !           200: static php_iconv_err_t _php_iconv_appendl(smart_str *d, const char *s, size_t l, iconv_t cd);
        !           201: static php_iconv_err_t _php_iconv_appendc(smart_str *d, const char c, iconv_t cd);
        !           202: 
        !           203: static void _php_iconv_show_error(php_iconv_err_t err, const char *out_charset, const char *in_charset TSRMLS_DC);
        !           204: 
        !           205: static php_iconv_err_t _php_iconv_strlen(unsigned int *pretval, const char *str, size_t nbytes, const char *enc);
        !           206: 
        !           207: static php_iconv_err_t _php_iconv_substr(smart_str *pretval, const char *str, size_t nbytes, int offset, int len, const char *enc);
        !           208: 
        !           209: static php_iconv_err_t _php_iconv_strpos(unsigned int *pretval, const char *haystk, size_t haystk_nbytes, const char *ndl, size_t ndl_nbytes, int offset, const char *enc);
        !           210: 
        !           211: static php_iconv_err_t _php_iconv_mime_encode(smart_str *pretval, const char *fname, size_t fname_nbytes, const char *fval, size_t fval_nbytes, unsigned int max_line_len, const char *lfchars, php_iconv_enc_scheme_t enc_scheme, const char *out_charset, const char *enc);
        !           212: 
        !           213: static php_iconv_err_t _php_iconv_mime_decode(smart_str *pretval, const char *str, size_t str_nbytes, const char *enc, const char **next_pos, int mode);
        !           214: 
        !           215: static php_iconv_err_t php_iconv_stream_filter_register_factory(TSRMLS_D);
        !           216: static php_iconv_err_t php_iconv_stream_filter_unregister_factory(TSRMLS_D);
        !           217: /* }}} */
        !           218: 
        !           219: /* {{{ static globals */
        !           220: static char _generic_superset_name[] = ICONV_UCS4_ENCODING;
        !           221: #define GENERIC_SUPERSET_NAME _generic_superset_name
        !           222: #define GENERIC_SUPERSET_NBYTES 4
        !           223: /* }}} */
        !           224: 
        !           225: static PHP_INI_MH(OnUpdateStringIconvCharset)
        !           226: {
        !           227:        if(new_value_length >= ICONV_CSNMAXLEN) {
        !           228:                return FAILURE;
        !           229:        }
        !           230:        OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
        !           231:        return SUCCESS;
        !           232: }
        !           233: 
        !           234: /* {{{ PHP_INI
        !           235:  */
        !           236: PHP_INI_BEGIN()
        !           237:        STD_PHP_INI_ENTRY("iconv.input_encoding",    ICONV_INPUT_ENCODING,    PHP_INI_ALL, OnUpdateStringIconvCharset, input_encoding,    zend_iconv_globals, iconv_globals)
        !           238:        STD_PHP_INI_ENTRY("iconv.output_encoding",   ICONV_OUTPUT_ENCODING,   PHP_INI_ALL, OnUpdateStringIconvCharset, output_encoding,   zend_iconv_globals, iconv_globals)
        !           239:        STD_PHP_INI_ENTRY("iconv.internal_encoding", ICONV_INTERNAL_ENCODING, PHP_INI_ALL, OnUpdateStringIconvCharset, internal_encoding, zend_iconv_globals, iconv_globals)
        !           240: PHP_INI_END()
        !           241: /* }}} */
        !           242: 
        !           243: /* {{{ PHP_MINIT_FUNCTION */
        !           244: PHP_MINIT_FUNCTION(miconv)
        !           245: {
        !           246:        char *version = "unknown";
        !           247: 
        !           248:        REGISTER_INI_ENTRIES();
        !           249: 
        !           250: #if HAVE_LIBICONV
        !           251:        {
        !           252:                static char buf[16];
        !           253:                snprintf(buf, sizeof(buf), "%d.%d",
        !           254:                    ((_libiconv_version >> 8) & 0x0f), (_libiconv_version & 0x0f)); 
        !           255:                version = buf;
        !           256:        }
        !           257: #elif HAVE_GLIBC_ICONV
        !           258:        version = (char *)gnu_get_libc_version();
        !           259: #elif defined(NETWARE)
        !           260:        version = "OS built-in";
        !           261: #endif
        !           262: 
        !           263: #ifdef PHP_ICONV_IMPL
        !           264:        REGISTER_STRING_CONSTANT("ICONV_IMPL", PHP_ICONV_IMPL, CONST_CS | CONST_PERSISTENT);
        !           265: #elif HAVE_LIBICONV
        !           266:        REGISTER_STRING_CONSTANT("ICONV_IMPL", "libiconv", CONST_CS | CONST_PERSISTENT);
        !           267: #elif defined(NETWARE)
        !           268:        REGISTER_STRING_CONSTANT("ICONV_IMPL", "Novell", CONST_CS | CONST_PERSISTENT);
        !           269: #else
        !           270:        REGISTER_STRING_CONSTANT("ICONV_IMPL", "unknown", CONST_CS | CONST_PERSISTENT);
        !           271: #endif
        !           272:        REGISTER_STRING_CONSTANT("ICONV_VERSION", version, CONST_CS | CONST_PERSISTENT);
        !           273: 
        !           274:        REGISTER_LONG_CONSTANT("ICONV_MIME_DECODE_STRICT", PHP_ICONV_MIME_DECODE_STRICT, CONST_CS | CONST_PERSISTENT);
        !           275:        REGISTER_LONG_CONSTANT("ICONV_MIME_DECODE_CONTINUE_ON_ERROR", PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR, CONST_CS | CONST_PERSISTENT);
        !           276: 
        !           277:        if (php_iconv_stream_filter_register_factory(TSRMLS_C) != PHP_ICONV_ERR_SUCCESS) {
        !           278:                return FAILURE;
        !           279:        }
        !           280: 
        !           281:        return SUCCESS;
        !           282: }
        !           283: /* }}} */
        !           284: 
        !           285: /* {{{ PHP_MSHUTDOWN_FUNCTION */
        !           286: PHP_MSHUTDOWN_FUNCTION(miconv)
        !           287: {
        !           288:        php_iconv_stream_filter_unregister_factory(TSRMLS_C);
        !           289:        UNREGISTER_INI_ENTRIES();
        !           290:        return SUCCESS;
        !           291: }
        !           292: /* }}} */
        !           293: 
        !           294: /* {{{ PHP_MINFO_FUNCTION */
        !           295: PHP_MINFO_FUNCTION(miconv)
        !           296: {
        !           297:        zval iconv_impl, iconv_ver;
        !           298: 
        !           299:        zend_get_constant("ICONV_IMPL", sizeof("ICONV_IMPL")-1, &iconv_impl TSRMLS_CC);
        !           300:        zend_get_constant("ICONV_VERSION", sizeof("ICONV_VERSION")-1, &iconv_ver TSRMLS_CC);
        !           301: 
        !           302:        php_info_print_table_start();
        !           303:        php_info_print_table_row(2, "iconv support", "enabled");
        !           304:        php_info_print_table_row(2, "iconv implementation", Z_STRVAL(iconv_impl));
        !           305:        php_info_print_table_row(2, "iconv library version", Z_STRVAL(iconv_ver));
        !           306:        php_info_print_table_end();
        !           307: 
        !           308:        DISPLAY_INI_ENTRIES();
        !           309: 
        !           310:        zval_dtor(&iconv_impl);
        !           311:        zval_dtor(&iconv_ver);
        !           312: }
        !           313: /* }}} */
        !           314: 
        !           315: /* {{{ _php_iconv_appendl() */
        !           316: static php_iconv_err_t _php_iconv_appendl(smart_str *d, const char *s, size_t l, iconv_t cd)
        !           317: {
        !           318:        const char *in_p = s;
        !           319:        size_t in_left = l;
        !           320:        char *out_p;
        !           321:        size_t out_left = 0;
        !           322:        size_t buf_growth = 128;
        !           323: #if !ICONV_SUPPORTS_ERRNO
        !           324:        size_t prev_in_left = in_left;
        !           325: #endif
        !           326: 
        !           327:        if (in_p != NULL) {
        !           328:                while (in_left > 0) {
        !           329:                        out_left = buf_growth - out_left;
        !           330:                        {
        !           331:                                size_t newlen;
        !           332:                                smart_str_alloc((d), out_left, 0);
        !           333:                        }
        !           334: 
        !           335:                        out_p = (d)->c + (d)->len;
        !           336: 
        !           337:                        if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
        !           338: #if ICONV_SUPPORTS_ERRNO
        !           339:                                switch (errno) { 
        !           340:                                        case EINVAL:
        !           341:                                                return PHP_ICONV_ERR_ILLEGAL_CHAR;
        !           342: 
        !           343:                                        case EILSEQ:
        !           344:                                                return PHP_ICONV_ERR_ILLEGAL_SEQ;
        !           345: 
        !           346:                                        case E2BIG:
        !           347:                                                break;
        !           348: 
        !           349:                                        default:
        !           350:                                                return PHP_ICONV_ERR_UNKNOWN;
        !           351:                                }
        !           352: #else
        !           353:                                if (prev_in_left == in_left) {
        !           354:                                        return PHP_ICONV_ERR_UNKNOWN;           
        !           355:                                }
        !           356: #endif
        !           357:                        }
        !           358: #if !ICONV_SUPPORTS_ERRNO
        !           359:                        prev_in_left = in_left;
        !           360: #endif
        !           361:                        (d)->len += (buf_growth - out_left);
        !           362:                        buf_growth <<= 1;
        !           363:                }
        !           364:        } else {
        !           365:                for (;;) {
        !           366:                        out_left = buf_growth - out_left;
        !           367:                        {
        !           368:                                size_t newlen;
        !           369:                                smart_str_alloc((d), out_left, 0);
        !           370:                        }
        !           371: 
        !           372:                        out_p = (d)->c + (d)->len;
        !           373: 
        !           374:                        if (iconv(cd, NULL, NULL, (char **) &out_p, &out_left) == (size_t)0) {
        !           375:                                (d)->len += (buf_growth - out_left);
        !           376:                                break;
        !           377:                        } else {
        !           378: #if ICONV_SUPPORTS_ERRNO
        !           379:                                if (errno != E2BIG) {
        !           380:                                        return PHP_ICONV_ERR_UNKNOWN;
        !           381:                                }
        !           382: #else
        !           383:                                if (out_left != 0) {
        !           384:                                        return PHP_ICONV_ERR_UNKNOWN;
        !           385:                                }       
        !           386: #endif
        !           387:                        }
        !           388:                        (d)->len += (buf_growth - out_left);
        !           389:                        buf_growth <<= 1;
        !           390:                }
        !           391:        }
        !           392:        return PHP_ICONV_ERR_SUCCESS;
        !           393: }
        !           394: /* }}} */
        !           395: 
        !           396: /* {{{ _php_iconv_appendc() */
        !           397: static php_iconv_err_t _php_iconv_appendc(smart_str *d, const char c, iconv_t cd)
        !           398: {
        !           399:        return _php_iconv_appendl(d, &c, 1, cd);
        !           400: }
        !           401: /* }}} */
        !           402: 
        !           403: /* {{{ php_iconv_string()
        !           404:  */
        !           405: PHP_ICONV_API php_iconv_err_t php_iconv_string(const char *in_p, size_t in_len,
        !           406:                                                        char **out, size_t *out_len,
        !           407:                                                        const char *out_charset, const char *in_charset)
        !           408: {
        !           409: #if !ICONV_SUPPORTS_ERRNO
        !           410:        size_t in_size, out_size, out_left;
        !           411:        char *out_buffer, *out_p;
        !           412:        iconv_t cd;
        !           413:        size_t result;
        !           414: 
        !           415:        *out = NULL;
        !           416:        *out_len = 0;
        !           417: 
        !           418:        /*
        !           419:          This is not the right way to get output size...
        !           420:          This is not space efficient for large text.
        !           421:          This is also problem for encoding like UTF-7/UTF-8/ISO-2022 which
        !           422:          a single char can be more than 4 bytes.
        !           423:          I added 15 extra bytes for safety. <yohgaki@php.net>
        !           424:        */
        !           425:        out_size = in_len * sizeof(int) + 15;
        !           426:        out_left = out_size;
        !           427: 
        !           428:        in_size = in_len;
        !           429: 
        !           430:        cd = iconv_open(out_charset, in_charset);
        !           431:        
        !           432:        if (cd == (iconv_t)(-1)) {
        !           433:                return PHP_ICONV_ERR_UNKNOWN;
        !           434:        }
        !           435: 
        !           436:        out_buffer = (char *) emalloc(out_size + 1);
        !           437:        out_p = out_buffer;
        !           438:        
        !           439: #ifdef NETWARE
        !           440:        result = iconv(cd, (char **) &in_p, &in_size, (char **)
        !           441: #else
        !           442:        result = iconv(cd, (const char **) &in_p, &in_size, (char **)
        !           443: #endif
        !           444:                                &out_p, &out_left);
        !           445:        
        !           446:        if (result == (size_t)(-1)) {
        !           447:                efree(out_buffer);
        !           448:                return PHP_ICONV_ERR_UNKNOWN;
        !           449:        }
        !           450: 
        !           451:        if (out_left < 8) {
        !           452:                out_buffer = (char *) erealloc(out_buffer, out_size + 8);
        !           453:        }
        !           454: 
        !           455:        /* flush the shift-out sequences */ 
        !           456:        result = iconv(cd, NULL, NULL, &out_p, &out_left);
        !           457: 
        !           458:        if (result == (size_t)(-1)) {
        !           459:                efree(out_buffer);
        !           460:                return PHP_ICONV_ERR_UNKNOWN;
        !           461:        }
        !           462: 
        !           463:        *out_len = out_size - out_left;
        !           464:        out_buffer[*out_len] = '\0';
        !           465:        *out = out_buffer;
        !           466: 
        !           467:        iconv_close(cd);
        !           468: 
        !           469:        return PHP_ICONV_ERR_SUCCESS;
        !           470: 
        !           471: #else
        !           472:        /*
        !           473:          iconv supports errno. Handle it better way.
        !           474:        */
        !           475:        iconv_t cd;
        !           476:        size_t in_left, out_size, out_left;
        !           477:        char *out_p, *out_buf, *tmp_buf;
        !           478:        size_t bsz, result = 0;
        !           479:        php_iconv_err_t retval = PHP_ICONV_ERR_SUCCESS;
        !           480: 
        !           481:        *out = NULL;
        !           482:        *out_len = 0;
        !           483: 
        !           484:        cd = iconv_open(out_charset, in_charset);
        !           485: 
        !           486:        if (cd == (iconv_t)(-1)) {
        !           487:                if (errno == EINVAL) {
        !           488:                        return PHP_ICONV_ERR_WRONG_CHARSET;
        !           489:                } else {
        !           490:                        return PHP_ICONV_ERR_CONVERTER;
        !           491:                }
        !           492:        }
        !           493:        in_left= in_len;
        !           494:        out_left = in_len + 32; /* Avoid realloc() most cases */ 
        !           495:        out_size = 0;
        !           496:        bsz = out_left;
        !           497:        out_buf = (char *) emalloc(bsz+1); 
        !           498:        out_p = out_buf;
        !           499: 
        !           500:        while (in_left > 0) {
        !           501:                result = iconv(cd, (char **) &in_p, &in_left, (char **) &out_p, &out_left);
        !           502:                out_size = bsz - out_left;
        !           503:                if (result == (size_t)(-1)) {
        !           504:                        if (errno == E2BIG && in_left > 0) {
        !           505:                                /* converted string is longer than out buffer */
        !           506:                                bsz += in_len;
        !           507: 
        !           508:                                tmp_buf = (char*) erealloc(out_buf, bsz+1);
        !           509:                                out_p = out_buf = tmp_buf;
        !           510:                                out_p += out_size;
        !           511:                                out_left = bsz - out_size;
        !           512:                                continue;       
        !           513:                        }
        !           514:                }
        !           515:                break;
        !           516:        }
        !           517: 
        !           518:        if (result != (size_t)(-1)) {
        !           519:                /* flush the shift-out sequences */ 
        !           520:                for (;;) {
        !           521:                        result = iconv(cd, NULL, NULL, (char **) &out_p, &out_left);
        !           522:                        out_size = bsz - out_left;
        !           523: 
        !           524:                        if (result != (size_t)(-1)) {
        !           525:                                break;
        !           526:                        }
        !           527: 
        !           528:                        if (errno == E2BIG) {
        !           529:                                bsz += 16;
        !           530:                                tmp_buf = (char *) erealloc(out_buf, bsz);
        !           531:                                
        !           532:                                out_p = out_buf = tmp_buf;
        !           533:                                out_p += out_size;
        !           534:                                out_left = bsz - out_size;
        !           535:                        } else {
        !           536:                                break;
        !           537:                        }
        !           538:                }
        !           539:        }
        !           540: 
        !           541:        iconv_close(cd);
        !           542: 
        !           543:        if (result == (size_t)(-1)) {
        !           544:                switch (errno) {
        !           545:                        case EINVAL:
        !           546:                                retval = PHP_ICONV_ERR_ILLEGAL_CHAR;
        !           547:                                break;
        !           548: 
        !           549:                        case EILSEQ:
        !           550:                                retval = PHP_ICONV_ERR_ILLEGAL_SEQ;
        !           551:                                break;
        !           552: 
        !           553:                        case E2BIG:
        !           554:                                /* should not happen */
        !           555:                                retval = PHP_ICONV_ERR_TOO_BIG;
        !           556:                                break;
        !           557: 
        !           558:                        default:
        !           559:                                /* other error */
        !           560:                                retval = PHP_ICONV_ERR_UNKNOWN;
        !           561:                                efree(out_buf);
        !           562:                                return PHP_ICONV_ERR_UNKNOWN;
        !           563:                }
        !           564:        }
        !           565:        *out_p = '\0';
        !           566:        *out = out_buf;
        !           567:        *out_len = out_size;
        !           568:        return retval;
        !           569: #endif
        !           570: }
        !           571: /* }}} */
        !           572: 
        !           573: /* {{{ _php_iconv_strlen() */
        !           574: static php_iconv_err_t _php_iconv_strlen(unsigned int *pretval, const char *str, size_t nbytes, const char *enc)
        !           575: {
        !           576:        char buf[GENERIC_SUPERSET_NBYTES*2];
        !           577: 
        !           578:        php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS;
        !           579: 
        !           580:        iconv_t cd;
        !           581: 
        !           582:        const char *in_p;
        !           583:        size_t in_left;
        !           584: 
        !           585:        char *out_p;
        !           586:        size_t out_left;
        !           587: 
        !           588:        unsigned int cnt;
        !           589: 
        !           590:        *pretval = (unsigned int)-1;
        !           591: 
        !           592:        cd = iconv_open(GENERIC_SUPERSET_NAME, enc);
        !           593: 
        !           594:        if (cd == (iconv_t)(-1)) {
        !           595: #if ICONV_SUPPORTS_ERRNO
        !           596:                if (errno == EINVAL) {
        !           597:                        return PHP_ICONV_ERR_WRONG_CHARSET;
        !           598:                } else {
        !           599:                        return PHP_ICONV_ERR_CONVERTER;
        !           600:                }
        !           601: #else
        !           602:                return PHP_ICONV_ERR_UNKNOWN;
        !           603: #endif
        !           604:        }
        !           605: 
        !           606:        errno = out_left = 0;
        !           607: 
        !           608:        for (in_p = str, in_left = nbytes, cnt = 0; in_left > 0; cnt+=2) {
        !           609:                size_t prev_in_left;
        !           610:                out_p = buf;
        !           611:                out_left = sizeof(buf);
        !           612: 
        !           613:                prev_in_left = in_left;
        !           614: 
        !           615:                if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
        !           616:                        if (prev_in_left == in_left) {
        !           617:                                break;
        !           618:                        }
        !           619:                }
        !           620:        }
        !           621: 
        !           622:        if (out_left > 0) {
        !           623:                cnt -= out_left / GENERIC_SUPERSET_NBYTES; 
        !           624:        }
        !           625: 
        !           626: #if ICONV_SUPPORTS_ERRNO
        !           627:        switch (errno) {
        !           628:                case EINVAL:
        !           629:                        err = PHP_ICONV_ERR_ILLEGAL_CHAR;
        !           630:                        break;
        !           631: 
        !           632:                case EILSEQ:
        !           633:                        err = PHP_ICONV_ERR_ILLEGAL_SEQ;
        !           634:                        break;
        !           635: 
        !           636:                case E2BIG:
        !           637:                case 0:
        !           638:                        *pretval = cnt;
        !           639:                        break;
        !           640: 
        !           641:                default:
        !           642:                        err = PHP_ICONV_ERR_UNKNOWN;
        !           643:                        break;
        !           644:        }
        !           645: #else
        !           646:        *pretval = cnt;
        !           647: #endif
        !           648: 
        !           649:        iconv_close(cd);
        !           650: 
        !           651:        return err;
        !           652: }
        !           653: 
        !           654: /* }}} */
        !           655: 
        !           656: /* {{{ _php_iconv_substr() */
        !           657: static php_iconv_err_t _php_iconv_substr(smart_str *pretval,
        !           658:        const char *str, size_t nbytes, int offset, int len, const char *enc)
        !           659: {
        !           660:        char buf[GENERIC_SUPERSET_NBYTES];
        !           661: 
        !           662:        php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS;
        !           663: 
        !           664:        iconv_t cd1, cd2;
        !           665: 
        !           666:        const char *in_p;
        !           667:        size_t in_left;
        !           668: 
        !           669:        char *out_p;
        !           670:        size_t out_left;
        !           671: 
        !           672:        unsigned int cnt;
        !           673:        int total_len;
        !           674:        
        !           675:        err = _php_iconv_strlen(&total_len, str, nbytes, enc);
        !           676:        if (err != PHP_ICONV_ERR_SUCCESS) {
        !           677:                return err;
        !           678:        }
        !           679:        
        !           680:        if (len < 0) {
        !           681:                if ((len += (total_len - offset)) < 0) {
        !           682:                        return PHP_ICONV_ERR_SUCCESS;
        !           683:                }
        !           684:        }
        !           685: 
        !           686:        if (offset < 0) {
        !           687:                if ((offset += total_len) < 0) {
        !           688:                        return PHP_ICONV_ERR_SUCCESS;
        !           689:                }
        !           690:        }
        !           691: 
        !           692:        if(len > total_len) {
        !           693:                len = total_len;
        !           694:        }
        !           695: 
        !           696: 
        !           697:        if (offset >= total_len) {
        !           698:                return PHP_ICONV_ERR_SUCCESS;
        !           699:        }
        !           700: 
        !           701:        if ((offset + len) > total_len ) {
        !           702:                /* trying to compute the length */
        !           703:                len = total_len - offset;
        !           704:        }
        !           705: 
        !           706:        if (len == 0) {
        !           707:                smart_str_appendl(pretval, "", 0);
        !           708:                smart_str_0(pretval);
        !           709:                return PHP_ICONV_ERR_SUCCESS;
        !           710:        }
        !           711:        
        !           712:        cd1 = iconv_open(GENERIC_SUPERSET_NAME, enc);
        !           713: 
        !           714:        if (cd1 == (iconv_t)(-1)) {
        !           715: #if ICONV_SUPPORTS_ERRNO
        !           716:                if (errno == EINVAL) {
        !           717:                        return PHP_ICONV_ERR_WRONG_CHARSET;
        !           718:                } else {
        !           719:                        return PHP_ICONV_ERR_CONVERTER;
        !           720:                }
        !           721: #else
        !           722:                return PHP_ICONV_ERR_UNKNOWN;
        !           723: #endif
        !           724:        }
        !           725: 
        !           726:        cd2 = (iconv_t)NULL;
        !           727:        errno = 0;
        !           728: 
        !           729:        for (in_p = str, in_left = nbytes, cnt = 0; in_left > 0 && len > 0; ++cnt) {
        !           730:                size_t prev_in_left;
        !           731:                out_p = buf;
        !           732:                out_left = sizeof(buf);
        !           733: 
        !           734:                prev_in_left = in_left;
        !           735: 
        !           736:                if (iconv(cd1, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
        !           737:                        if (prev_in_left == in_left) {
        !           738:                                break;
        !           739:                        }
        !           740:                }
        !           741: 
        !           742:                if (cnt >= (unsigned int)offset) {
        !           743:                        if (cd2 == (iconv_t)NULL) {
        !           744:                                cd2 = iconv_open(enc, GENERIC_SUPERSET_NAME);
        !           745: 
        !           746:                                if (cd2 == (iconv_t)(-1)) {
        !           747:                                        cd2 = (iconv_t)NULL;
        !           748: #if ICONV_SUPPORTS_ERRNO
        !           749:                                        if (errno == EINVAL) {
        !           750:                                                err = PHP_ICONV_ERR_WRONG_CHARSET;
        !           751:                                        } else {
        !           752:                                                err = PHP_ICONV_ERR_CONVERTER;
        !           753:                                        }
        !           754: #else
        !           755:                                        err = PHP_ICONV_ERR_UNKNOWN;
        !           756: #endif
        !           757:                                        break;
        !           758:                                }
        !           759:                        }
        !           760: 
        !           761:                        if (_php_iconv_appendl(pretval, buf, sizeof(buf), cd2) != PHP_ICONV_ERR_SUCCESS) {
        !           762:                                break;
        !           763:                        }
        !           764:                        --len;
        !           765:                }
        !           766: 
        !           767:        }
        !           768: 
        !           769: #if ICONV_SUPPORTS_ERRNO
        !           770:        switch (errno) {
        !           771:                case EINVAL:
        !           772:                        err = PHP_ICONV_ERR_ILLEGAL_CHAR;
        !           773:                        break;
        !           774: 
        !           775:                case EILSEQ:
        !           776:                        err = PHP_ICONV_ERR_ILLEGAL_SEQ;
        !           777:                        break;
        !           778: 
        !           779:                case E2BIG:
        !           780:                        break;
        !           781:        }
        !           782: #endif
        !           783:        if (err == PHP_ICONV_ERR_SUCCESS) {
        !           784:                if (cd2 != (iconv_t)NULL) {
        !           785:                        _php_iconv_appendl(pretval, NULL, 0, cd2);
        !           786:                }
        !           787:                smart_str_0(pretval);
        !           788:        }
        !           789: 
        !           790:        if (cd1 != (iconv_t)NULL) {
        !           791:                iconv_close(cd1);
        !           792:        }
        !           793: 
        !           794:        if (cd2 != (iconv_t)NULL) {
        !           795:                iconv_close(cd2);
        !           796:        }       
        !           797:        return err;
        !           798: }
        !           799: 
        !           800: /* }}} */
        !           801: 
        !           802: /* {{{ _php_iconv_strpos() */
        !           803: static php_iconv_err_t _php_iconv_strpos(unsigned int *pretval,
        !           804:        const char *haystk, size_t haystk_nbytes,
        !           805:        const char *ndl, size_t ndl_nbytes,
        !           806:        int offset, const char *enc)
        !           807: {
        !           808:        char buf[GENERIC_SUPERSET_NBYTES];
        !           809: 
        !           810:        php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS;
        !           811: 
        !           812:        iconv_t cd;
        !           813: 
        !           814:        const char *in_p;
        !           815:        size_t in_left;
        !           816: 
        !           817:        char *out_p;
        !           818:        size_t out_left;
        !           819: 
        !           820:        unsigned int cnt;
        !           821: 
        !           822:        char *ndl_buf;
        !           823:        const char *ndl_buf_p;
        !           824:        size_t ndl_buf_len, ndl_buf_left;
        !           825: 
        !           826:        unsigned int match_ofs;
        !           827: 
        !           828:        *pretval = (unsigned int)-1;
        !           829: 
        !           830:        err = php_iconv_string(ndl, ndl_nbytes,
        !           831:                &ndl_buf, &ndl_buf_len, GENERIC_SUPERSET_NAME, enc);
        !           832: 
        !           833:        if (err != PHP_ICONV_ERR_SUCCESS) {
        !           834:                if (ndl_buf != NULL) {
        !           835:                        efree(ndl_buf);
        !           836:                }
        !           837:                return err;
        !           838:        }
        !           839: 
        !           840:        cd = iconv_open(GENERIC_SUPERSET_NAME, enc);
        !           841: 
        !           842:        if (cd == (iconv_t)(-1)) {
        !           843:                if (ndl_buf != NULL) {
        !           844:                        efree(ndl_buf);
        !           845:                }
        !           846: #if ICONV_SUPPORTS_ERRNO
        !           847:                if (errno == EINVAL) {
        !           848:                        return PHP_ICONV_ERR_WRONG_CHARSET;
        !           849:                } else {
        !           850:                        return PHP_ICONV_ERR_CONVERTER;
        !           851:                }
        !           852: #else
        !           853:                return PHP_ICONV_ERR_UNKNOWN;
        !           854: #endif
        !           855:        }
        !           856: 
        !           857:        ndl_buf_p = ndl_buf;
        !           858:        ndl_buf_left = ndl_buf_len;
        !           859:        match_ofs = (unsigned int)-1;
        !           860: 
        !           861:        for (in_p = haystk, in_left = haystk_nbytes, cnt = 0; in_left > 0; ++cnt) {
        !           862:                size_t prev_in_left;
        !           863:                out_p = buf;
        !           864:                out_left = sizeof(buf);
        !           865: 
        !           866:                prev_in_left = in_left;
        !           867: 
        !           868:                if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
        !           869:                        if (prev_in_left == in_left) {
        !           870: #if ICONV_SUPPORTS_ERRNO
        !           871:                                switch (errno) {
        !           872:                                        case EINVAL:
        !           873:                                                err = PHP_ICONV_ERR_ILLEGAL_CHAR;
        !           874:                                                break;
        !           875: 
        !           876:                                        case EILSEQ:
        !           877:                                                err = PHP_ICONV_ERR_ILLEGAL_SEQ;
        !           878:                                                break;
        !           879: 
        !           880:                                        case E2BIG:
        !           881:                                                break;
        !           882: 
        !           883:                                        default:
        !           884:                                                err = PHP_ICONV_ERR_UNKNOWN;
        !           885:                                                break;
        !           886:                                }
        !           887: #endif
        !           888:                                break;
        !           889:                        }
        !           890:                }
        !           891:                if (offset >= 0) {
        !           892:                        if (cnt >= (unsigned int)offset) {
        !           893:                                if (_php_iconv_memequal(buf, ndl_buf_p, sizeof(buf))) {
        !           894:                                        if (match_ofs == (unsigned int)-1) {
        !           895:                                                match_ofs = cnt;
        !           896:                                        }
        !           897:                                        ndl_buf_p += GENERIC_SUPERSET_NBYTES;
        !           898:                                        ndl_buf_left -= GENERIC_SUPERSET_NBYTES;
        !           899:                                        if (ndl_buf_left == 0) {
        !           900:                                                *pretval = match_ofs;
        !           901:                                                break;
        !           902:                                        }
        !           903:                                } else {
        !           904:                                        unsigned int i, j, lim;
        !           905: 
        !           906:                                        i = 0;
        !           907:                                        j = GENERIC_SUPERSET_NBYTES;
        !           908:                                        lim = (unsigned int)(ndl_buf_p - ndl_buf);
        !           909: 
        !           910:                                        while (j < lim) {
        !           911:                                                if (_php_iconv_memequal(&ndl_buf[j], &ndl_buf[i],
        !           912:                                                           GENERIC_SUPERSET_NBYTES)) {
        !           913:                                                        i += GENERIC_SUPERSET_NBYTES;
        !           914:                                                } else {
        !           915:                                                        j -= i;
        !           916:                                                        i = 0;
        !           917:                                                }
        !           918:                                                j += GENERIC_SUPERSET_NBYTES;
        !           919:                                        }
        !           920: 
        !           921:                                        if (_php_iconv_memequal(buf, &ndl_buf[i], sizeof(buf))) {
        !           922:                                                match_ofs += (lim - i) / GENERIC_SUPERSET_NBYTES;
        !           923:                                                i += GENERIC_SUPERSET_NBYTES;
        !           924:                                                ndl_buf_p = &ndl_buf[i];
        !           925:                                                ndl_buf_left = ndl_buf_len - i;
        !           926:                                        } else {
        !           927:                                                match_ofs = (unsigned int)-1;
        !           928:                                                ndl_buf_p = ndl_buf;
        !           929:                                                ndl_buf_left = ndl_buf_len;
        !           930:                                        }
        !           931:                                }
        !           932:                        }
        !           933:                } else {
        !           934:                        if (_php_iconv_memequal(buf, ndl_buf_p, sizeof(buf))) {
        !           935:                                if (match_ofs == (unsigned int)-1) {
        !           936:                                        match_ofs = cnt;
        !           937:                                }
        !           938:                                ndl_buf_p += GENERIC_SUPERSET_NBYTES;
        !           939:                                ndl_buf_left -= GENERIC_SUPERSET_NBYTES;
        !           940:                                if (ndl_buf_left == 0) {
        !           941:                                        *pretval = match_ofs;
        !           942:                                        ndl_buf_p = ndl_buf;
        !           943:                                        ndl_buf_left = ndl_buf_len;
        !           944:                                        match_ofs = -1;
        !           945:                                }
        !           946:                        } else {
        !           947:                                unsigned int i, j, lim;
        !           948: 
        !           949:                                i = 0;
        !           950:                                j = GENERIC_SUPERSET_NBYTES;
        !           951:                                lim = (unsigned int)(ndl_buf_p - ndl_buf);
        !           952: 
        !           953:                                while (j < lim) {
        !           954:                                        if (_php_iconv_memequal(&ndl_buf[j], &ndl_buf[i],
        !           955:                                                           GENERIC_SUPERSET_NBYTES)) {
        !           956:                                                i += GENERIC_SUPERSET_NBYTES;
        !           957:                                        } else {
        !           958:                                                j -= i;
        !           959:                                                i = 0;
        !           960:                                        }
        !           961:                                        j += GENERIC_SUPERSET_NBYTES;
        !           962:                                }
        !           963: 
        !           964:                                if (_php_iconv_memequal(buf, &ndl_buf[i], sizeof(buf))) {
        !           965:                                        match_ofs += (lim - i) / GENERIC_SUPERSET_NBYTES;
        !           966:                                        i += GENERIC_SUPERSET_NBYTES;
        !           967:                                        ndl_buf_p = &ndl_buf[i];
        !           968:                                        ndl_buf_left = ndl_buf_len - i;
        !           969:                                } else {
        !           970:                                        match_ofs = (unsigned int)-1;
        !           971:                                        ndl_buf_p = ndl_buf;
        !           972:                                        ndl_buf_left = ndl_buf_len;
        !           973:                                }
        !           974:                        }
        !           975:                }
        !           976:        }
        !           977: 
        !           978:        if (ndl_buf) {
        !           979:                efree(ndl_buf);
        !           980:        }
        !           981:        
        !           982:        iconv_close(cd);
        !           983: 
        !           984:        return err;
        !           985: }
        !           986: /* }}} */
        !           987: 
        !           988: /* {{{ _php_iconv_mime_encode() */
        !           989: static php_iconv_err_t _php_iconv_mime_encode(smart_str *pretval, const char *fname, size_t fname_nbytes, const char *fval, size_t fval_nbytes, unsigned int max_line_len, const char *lfchars, php_iconv_enc_scheme_t enc_scheme, const char *out_charset, const char *enc)
        !           990: {
        !           991:        php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS;
        !           992:        iconv_t cd = (iconv_t)(-1), cd_pl = (iconv_t)(-1);
        !           993:        unsigned int char_cnt = 0;
        !           994:        size_t out_charset_len;
        !           995:        size_t lfchars_len;
        !           996:        char *buf = NULL;
        !           997:        char *encoded = NULL;
        !           998:        size_t encoded_len;
        !           999:        const char *in_p;
        !          1000:        size_t in_left;
        !          1001:        char *out_p;
        !          1002:        size_t out_left;
        !          1003:        static int qp_table[256] = {
        !          1004:                3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x00 */
        !          1005:                3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x10 */
        !          1006:                3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x20 */
        !          1007:                1, 1, 1, 1, 1, 1, 1 ,1, 1, 1, 1, 1, 1, 3, 1, 3, /* 0x30 */
        !          1008:                1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 */
        !          1009:                1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, /* 0x50 */
        !          1010:                1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 */
        !          1011:                1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, /* 0x70 */
        !          1012:                3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x80 */
        !          1013:                3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x90 */
        !          1014:                3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xA0 */
        !          1015:                3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xB0 */
        !          1016:                3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xC0 */
        !          1017:                3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xD0 */
        !          1018:                3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xE0 */
        !          1019:                3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3  /* 0xF0 */
        !          1020:        };
        !          1021: 
        !          1022:        out_charset_len = strlen(out_charset);
        !          1023:        lfchars_len = strlen(lfchars);
        !          1024: 
        !          1025:        if ((fname_nbytes + 2) >= max_line_len
        !          1026:                || (out_charset_len + 12) >= max_line_len) {
        !          1027:                /* field name is too long */
        !          1028:                err = PHP_ICONV_ERR_TOO_BIG; 
        !          1029:                goto out;
        !          1030:        }
        !          1031: 
        !          1032:        cd_pl = iconv_open(ICONV_ASCII_ENCODING, enc);
        !          1033:        if (cd_pl == (iconv_t)(-1)) {
        !          1034: #if ICONV_SUPPORTS_ERRNO
        !          1035:                if (errno == EINVAL) {
        !          1036:                        err = PHP_ICONV_ERR_WRONG_CHARSET;
        !          1037:                } else {
        !          1038:                        err = PHP_ICONV_ERR_CONVERTER;
        !          1039:                }
        !          1040: #else
        !          1041:                err = PHP_ICONV_ERR_UNKNOWN;
        !          1042: #endif
        !          1043:                goto out;
        !          1044:        }
        !          1045: 
        !          1046:        cd = iconv_open(out_charset, enc);
        !          1047:        if (cd == (iconv_t)(-1)) {
        !          1048: #if ICONV_SUPPORTS_ERRNO
        !          1049:                if (errno == EINVAL) {
        !          1050:                        err = PHP_ICONV_ERR_WRONG_CHARSET;
        !          1051:                } else {
        !          1052:                        err = PHP_ICONV_ERR_CONVERTER;
        !          1053:                }
        !          1054: #else
        !          1055:                err = PHP_ICONV_ERR_UNKNOWN;
        !          1056: #endif
        !          1057:                goto out;
        !          1058:        }
        !          1059: 
        !          1060:        buf = safe_emalloc(1, max_line_len, 5);
        !          1061: 
        !          1062:        char_cnt = max_line_len;
        !          1063: 
        !          1064:        _php_iconv_appendl(pretval, fname, fname_nbytes, cd_pl);
        !          1065:        char_cnt -= fname_nbytes;
        !          1066:        smart_str_appendl(pretval, ": ", sizeof(": ") - 1);
        !          1067:        char_cnt -= 2;
        !          1068: 
        !          1069:        in_p = fval;
        !          1070:        in_left = fval_nbytes; 
        !          1071: 
        !          1072:        do {
        !          1073:                size_t prev_in_left;
        !          1074:                size_t out_size;
        !          1075: 
        !          1076:                if (char_cnt < (out_charset_len + 12)) {
        !          1077:                        /* lfchars must be encoded in ASCII here*/
        !          1078:                        smart_str_appendl(pretval, lfchars, lfchars_len);
        !          1079:                        smart_str_appendc(pretval, ' ');
        !          1080:                        char_cnt = max_line_len - 1;
        !          1081:                } 
        !          1082:  
        !          1083:                smart_str_appendl(pretval, "=?", sizeof("=?") - 1);
        !          1084:                char_cnt -= 2;
        !          1085:                smart_str_appendl(pretval, out_charset, out_charset_len);
        !          1086:                char_cnt -= out_charset_len;
        !          1087:                smart_str_appendc(pretval, '?');
        !          1088:                char_cnt --;
        !          1089: 
        !          1090:                switch (enc_scheme) {
        !          1091:                        case PHP_ICONV_ENC_SCHEME_BASE64: {
        !          1092:                                size_t ini_in_left;
        !          1093:                                const char *ini_in_p;
        !          1094:                                size_t out_reserved = 4;
        !          1095:                                int dummy;
        !          1096: 
        !          1097:                                smart_str_appendc(pretval, 'B');
        !          1098:                                char_cnt--;
        !          1099:                                smart_str_appendc(pretval, '?');
        !          1100:                                char_cnt--;
        !          1101: 
        !          1102:                                prev_in_left = ini_in_left = in_left;
        !          1103:                                ini_in_p = in_p;
        !          1104: 
        !          1105:                                out_size = (char_cnt - 2) / 4 * 3;
        !          1106: 
        !          1107:                                for (;;) {
        !          1108:                                        out_p = buf;
        !          1109: 
        !          1110:                                        if (out_size <= out_reserved) {
        !          1111:                                                err = PHP_ICONV_ERR_TOO_BIG;
        !          1112:                                                goto out;
        !          1113:                                        }
        !          1114: 
        !          1115:                                        out_left = out_size - out_reserved;
        !          1116: 
        !          1117:                                        if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
        !          1118: #if ICONV_SUPPORTS_ERRNO
        !          1119:                                                switch (errno) {
        !          1120:                                                        case EINVAL:
        !          1121:                                                                err = PHP_ICONV_ERR_ILLEGAL_CHAR;
        !          1122:                                                                goto out;
        !          1123: 
        !          1124:                                                        case EILSEQ:
        !          1125:                                                                err = PHP_ICONV_ERR_ILLEGAL_SEQ;
        !          1126:                                                                goto out;
        !          1127: 
        !          1128:                                                        case E2BIG:
        !          1129:                                                                if (prev_in_left == in_left) {
        !          1130:                                                                        err = PHP_ICONV_ERR_TOO_BIG;
        !          1131:                                                                        goto out;
        !          1132:                                                                }
        !          1133:                                                                break;
        !          1134: 
        !          1135:                                                        default:
        !          1136:                                                                err = PHP_ICONV_ERR_UNKNOWN;
        !          1137:                                                                goto out;
        !          1138:                                                }
        !          1139: #else
        !          1140:                                                if (prev_in_left == in_left) {
        !          1141:                                                        err = PHP_ICONV_ERR_UNKNOWN;
        !          1142:                                                        goto out;
        !          1143:                                                }
        !          1144: #endif
        !          1145:                                        }
        !          1146: 
        !          1147:                                        out_left += out_reserved;
        !          1148: 
        !          1149:                                        if (iconv(cd, NULL, NULL, (char **) &out_p, &out_left) == (size_t)-1) {
        !          1150: #if ICONV_SUPPORTS_ERRNO
        !          1151:                                                if (errno != E2BIG) {
        !          1152:                                                        err = PHP_ICONV_ERR_UNKNOWN;
        !          1153:                                                        goto out;
        !          1154:                                                }
        !          1155: #else
        !          1156:                                                if (out_left != 0) {
        !          1157:                                                        err = PHP_ICONV_ERR_UNKNOWN;
        !          1158:                                                        goto out;
        !          1159:                                                }
        !          1160: #endif
        !          1161:                                        } else {
        !          1162:                                                break;
        !          1163:                                        }
        !          1164: 
        !          1165:                                        if (iconv(cd, NULL, NULL, NULL, NULL) == (size_t)-1) {
        !          1166:                                                err = PHP_ICONV_ERR_UNKNOWN;
        !          1167:                                                goto out;
        !          1168:                                        }
        !          1169: 
        !          1170:                                        out_reserved += 4;
        !          1171:                                        in_left = ini_in_left;
        !          1172:                                        in_p = ini_in_p;
        !          1173:                                }
        !          1174: 
        !          1175:                                prev_in_left = in_left;
        !          1176: 
        !          1177:                                encoded = (char *) php_base64_encode((unsigned char *) buf, (int)(out_size - out_left), &dummy);
        !          1178:                                encoded_len = (size_t)dummy;
        !          1179: 
        !          1180:                                if (char_cnt < encoded_len) {
        !          1181:                                        /* something went wrong! */
        !          1182:                                        err = PHP_ICONV_ERR_UNKNOWN;
        !          1183:                                        goto out;
        !          1184:                                }
        !          1185: 
        !          1186:                                smart_str_appendl(pretval, encoded, encoded_len);
        !          1187:                                char_cnt -= encoded_len;
        !          1188:                                smart_str_appendl(pretval, "?=", sizeof("?=") - 1);
        !          1189:                                char_cnt -= 2;
        !          1190: 
        !          1191:                                efree(encoded);
        !          1192:                                encoded = NULL;
        !          1193:                        } break; /* case PHP_ICONV_ENC_SCHEME_BASE64: */
        !          1194: 
        !          1195:                        case PHP_ICONV_ENC_SCHEME_QPRINT: {
        !          1196:                                size_t ini_in_left;
        !          1197:                                const char *ini_in_p;
        !          1198:                                const unsigned char *p;
        !          1199:                                size_t nbytes_required;
        !          1200: 
        !          1201:                                smart_str_appendc(pretval, 'Q');
        !          1202:                                char_cnt--;
        !          1203:                                smart_str_appendc(pretval, '?');
        !          1204:                                char_cnt--;
        !          1205: 
        !          1206:                                prev_in_left = ini_in_left = in_left;
        !          1207:                                ini_in_p = in_p;
        !          1208: 
        !          1209:                                for (out_size = (char_cnt - 2) / 3; out_size > 0;) {
        !          1210:                                        size_t prev_out_left;
        !          1211: 
        !          1212:                                        nbytes_required = 0;
        !          1213: 
        !          1214:                                        out_p = buf;
        !          1215:                                        out_left = out_size;
        !          1216: 
        !          1217:                                        if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
        !          1218: #if ICONV_SUPPORTS_ERRNO
        !          1219:                                                switch (errno) {
        !          1220:                                                        case EINVAL:
        !          1221:                                                                err = PHP_ICONV_ERR_ILLEGAL_CHAR;
        !          1222:                                                                goto out;
        !          1223: 
        !          1224:                                                        case EILSEQ:
        !          1225:                                                                err = PHP_ICONV_ERR_ILLEGAL_SEQ;
        !          1226:                                                                goto out;
        !          1227: 
        !          1228:                                                        case E2BIG:
        !          1229:                                                                if (prev_in_left == in_left) {
        !          1230:                                                                        err = PHP_ICONV_ERR_UNKNOWN;
        !          1231:                                                                        goto out;
        !          1232:                                                                }
        !          1233:                                                                break;
        !          1234:        
        !          1235:                                                        default:
        !          1236:                                                                err = PHP_ICONV_ERR_UNKNOWN;
        !          1237:                                                                goto out;
        !          1238:                                                }
        !          1239: #else
        !          1240:                                                if (prev_in_left == in_left) {
        !          1241:                                                        err = PHP_ICONV_ERR_UNKNOWN;
        !          1242:                                                        goto out;
        !          1243:                                                }
        !          1244: #endif
        !          1245:                                        }
        !          1246: 
        !          1247:                                        prev_out_left = out_left;
        !          1248:                                        if (iconv(cd, NULL, NULL, (char **) &out_p, &out_left) == (size_t)-1) {
        !          1249: #if ICONV_SUPPORTS_ERRNO
        !          1250:                                                if (errno != E2BIG) {
        !          1251:                                                        err = PHP_ICONV_ERR_UNKNOWN;
        !          1252:                                                        goto out;
        !          1253:                                                }
        !          1254: #else
        !          1255:                                                if (out_left == prev_out_left) {
        !          1256:                                                        err = PHP_ICONV_ERR_UNKNOWN;
        !          1257:                                                        goto out;
        !          1258:                                                }
        !          1259: #endif
        !          1260:                                        }
        !          1261: 
        !          1262:                                        for (p = (unsigned char *)buf; p < (unsigned char *)out_p; p++) {
        !          1263:                                                nbytes_required += qp_table[*p];
        !          1264:                                        }
        !          1265: 
        !          1266:                                        if (nbytes_required <= char_cnt - 2) {
        !          1267:                                                break;
        !          1268:                                        }
        !          1269: 
        !          1270:                                        out_size -= ((nbytes_required - (char_cnt - 2)) + 1) / 3;
        !          1271:                                        in_left = ini_in_left;
        !          1272:                                        in_p = ini_in_p;
        !          1273:                                }
        !          1274: 
        !          1275:                                for (p = (unsigned char *)buf; p < (unsigned char *)out_p; p++) {
        !          1276:                                        if (qp_table[*p] == 1) {
        !          1277:                                                smart_str_appendc(pretval, *(char *)p);
        !          1278:                                                char_cnt--;
        !          1279:                                        } else {
        !          1280:                                                static char qp_digits[] = "0123456789ABCDEF";
        !          1281:                                                smart_str_appendc(pretval, '=');
        !          1282:                                                smart_str_appendc(pretval, qp_digits[(*p >> 4) & 0x0f]);
        !          1283:                                                smart_str_appendc(pretval, qp_digits[(*p & 0x0f)]);
        !          1284:                                                char_cnt -= 3;
        !          1285:                                        }
        !          1286:                                }
        !          1287: 
        !          1288:                                smart_str_appendl(pretval, "?=", sizeof("?=") - 1);
        !          1289:                                char_cnt -= 2;
        !          1290: 
        !          1291:                                if (iconv(cd, NULL, NULL, NULL, NULL) == (size_t)-1) {
        !          1292:                                        err = PHP_ICONV_ERR_UNKNOWN;
        !          1293:                                        goto out;
        !          1294:                                }
        !          1295: 
        !          1296:                        } break; /* case PHP_ICONV_ENC_SCHEME_QPRINT: */
        !          1297:                }
        !          1298:        } while (in_left > 0);
        !          1299: 
        !          1300:        smart_str_0(pretval);
        !          1301: 
        !          1302: out:
        !          1303:        if (cd != (iconv_t)(-1)) {
        !          1304:                iconv_close(cd);
        !          1305:        }
        !          1306:        if (cd_pl != (iconv_t)(-1)) {
        !          1307:                iconv_close(cd_pl);
        !          1308:        }
        !          1309:        if (encoded != NULL) {
        !          1310:                efree(encoded);
        !          1311:        }       
        !          1312:        if (buf != NULL) {
        !          1313:                efree(buf);
        !          1314:        }
        !          1315:        return err;
        !          1316: }
        !          1317: /* }}} */
        !          1318: 
        !          1319: /* {{{ _php_iconv_mime_decode() */
        !          1320: static php_iconv_err_t _php_iconv_mime_decode(smart_str *pretval, const char *str, size_t str_nbytes, const char *enc, const char **next_pos, int mode)
        !          1321: {
        !          1322:        php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS;
        !          1323: 
        !          1324:        iconv_t cd = (iconv_t)(-1), cd_pl = (iconv_t)(-1);
        !          1325: 
        !          1326:        const char *p1;
        !          1327:        size_t str_left;
        !          1328:        unsigned int scan_stat = 0;
        !          1329:        const char *csname = NULL;
        !          1330:        size_t csname_len; 
        !          1331:        const char *encoded_text = NULL;
        !          1332:        size_t encoded_text_len = 0;
        !          1333:        const char *encoded_word = NULL;
        !          1334:        const char *spaces = NULL;
        !          1335: 
        !          1336:        php_iconv_enc_scheme_t enc_scheme = PHP_ICONV_ENC_SCHEME_BASE64;
        !          1337: 
        !          1338:        if (next_pos != NULL) {
        !          1339:                *next_pos = NULL;
        !          1340:        }
        !          1341: 
        !          1342:        cd_pl = iconv_open(enc, ICONV_ASCII_ENCODING);
        !          1343: 
        !          1344:        if (cd_pl == (iconv_t)(-1)) {
        !          1345: #if ICONV_SUPPORTS_ERRNO
        !          1346:                if (errno == EINVAL) {
        !          1347:                        err = PHP_ICONV_ERR_WRONG_CHARSET;
        !          1348:                } else {
        !          1349:                        err = PHP_ICONV_ERR_CONVERTER;
        !          1350:                }
        !          1351: #else
        !          1352:                err = PHP_ICONV_ERR_UNKNOWN;
        !          1353: #endif
        !          1354:                goto out;
        !          1355:        }
        !          1356: 
        !          1357:        p1 = str;
        !          1358:        for (str_left = str_nbytes; str_left > 0; str_left--, p1++) {
        !          1359:                int eos = 0;
        !          1360: 
        !          1361:                switch (scan_stat) {
        !          1362:                        case 0: /* expecting any character */
        !          1363:                                switch (*p1) {
        !          1364:                                        case '\r': /* part of an EOL sequence? */
        !          1365:                                                scan_stat = 7;
        !          1366:                                                break;
        !          1367: 
        !          1368:                                        case '\n':
        !          1369:                                                scan_stat = 8;  
        !          1370:                                                break;
        !          1371: 
        !          1372:                                        case '=': /* first letter of an encoded chunk */
        !          1373:                                                encoded_word = p1;
        !          1374:                                                scan_stat = 1;
        !          1375:                                                break;
        !          1376: 
        !          1377:                                        case ' ': case '\t': /* a chunk of whitespaces */
        !          1378:                                                spaces = p1;
        !          1379:                                                scan_stat = 11;
        !          1380:                                                break;
        !          1381: 
        !          1382:                                        default: /* first letter of a non-encoded word */
        !          1383:                                                _php_iconv_appendc(pretval, *p1, cd_pl);
        !          1384:                                                encoded_word = NULL;
        !          1385:                                                if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
        !          1386:                                                        scan_stat = 12;
        !          1387:                                                }
        !          1388:                                                break;
        !          1389:                                }
        !          1390:                                break;
        !          1391: 
        !          1392:                        case 1: /* expecting a delimiter */
        !          1393:                                if (*p1 != '?') {
        !          1394:                                        err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl); 
        !          1395:                                        if (err != PHP_ICONV_ERR_SUCCESS) {
        !          1396:                                                goto out;
        !          1397:                                        }
        !          1398:                                        encoded_word = NULL;
        !          1399:                                        if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
        !          1400:                                                scan_stat = 12;
        !          1401:                                        } else {
        !          1402:                                                scan_stat = 0;
        !          1403:                                        }
        !          1404:                                        break;
        !          1405:                                }
        !          1406:                                csname = p1 + 1;
        !          1407:                                scan_stat = 2;
        !          1408:                                break;
        !          1409:                        
        !          1410:                        case 2: /* expecting a charset name */
        !          1411:                                switch (*p1) {
        !          1412:                                        case '?': /* normal delimiter: encoding scheme follows */
        !          1413:                                                scan_stat = 3;
        !          1414:                                                break;
        !          1415: 
        !          1416:                                        case '*': /* new style delimiter: locale id follows */
        !          1417:                                                scan_stat = 10;
        !          1418:                                                break;
        !          1419:                                } 
        !          1420:                                if (scan_stat != 2) {
        !          1421:                                        char tmpbuf[80];
        !          1422: 
        !          1423:                                        if (csname == NULL) {
        !          1424:                                                err = PHP_ICONV_ERR_MALFORMED;
        !          1425:                                                goto out;
        !          1426:                                        }
        !          1427: 
        !          1428:                                        csname_len = (size_t)(p1 - csname);
        !          1429: 
        !          1430:                                        if (csname_len > sizeof(tmpbuf) - 1) {
        !          1431:                                                if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
        !          1432:                                                        err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl); 
        !          1433:                                                        if (err != PHP_ICONV_ERR_SUCCESS) {
        !          1434:                                                                goto out;
        !          1435:                                                        }
        !          1436:                                                        encoded_word = NULL;
        !          1437:                                                        if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
        !          1438:                                                                scan_stat = 12;
        !          1439:                                                        } else {
        !          1440:                                                                scan_stat = 0;
        !          1441:                                                        }
        !          1442:                                                        break;
        !          1443:                                                } else {
        !          1444:                                                        err = PHP_ICONV_ERR_MALFORMED;
        !          1445:                                                        goto out;
        !          1446:                                                }
        !          1447:                                        }
        !          1448: 
        !          1449:                                        memcpy(tmpbuf, csname, csname_len);
        !          1450:                                        tmpbuf[csname_len] = '\0';
        !          1451: 
        !          1452:                                        if (cd != (iconv_t)(-1)) {
        !          1453:                                                iconv_close(cd);
        !          1454:                                        }
        !          1455: 
        !          1456:                                        cd = iconv_open(enc, tmpbuf);
        !          1457: 
        !          1458:                                        if (cd == (iconv_t)(-1)) {
        !          1459:                                                if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
        !          1460:                                                        /* Bad character set, but the user wants us to
        !          1461:                                                         * press on. In this case, we'll just insert the
        !          1462:                                                         * undecoded encoded word, since there isn't really
        !          1463:                                                         * a more sensible behaviour available; the only
        !          1464:                                                         * other options are to swallow the encoded word
        !          1465:                                                         * entirely or decode it with an arbitrarily chosen
        !          1466:                                                         * single byte encoding, both of which seem to have
        !          1467:                                                         * a higher WTF factor than leaving it undecoded.
        !          1468:                                                         *
        !          1469:                                                         * Given this approach, we need to skip ahead to
        !          1470:                                                         * the end of the encoded word. */
        !          1471:                                                        int qmarks = 2;
        !          1472:                                                        while (qmarks > 0 && str_left > 1) {
        !          1473:                                                                if (*(++p1) == '?') {
        !          1474:                                                                        --qmarks;
        !          1475:                                                                }
        !          1476:                                                                --str_left;
        !          1477:                                                        }
        !          1478: 
        !          1479:                                                        /* Look ahead to check for the terminating = that
        !          1480:                                                         * should be there as well; if it's there, we'll
        !          1481:                                                         * also include that. If it's not, there isn't much
        !          1482:                                                         * we can do at this point. */
        !          1483:                                                        if (*(p1 + 1) == '=') {
        !          1484:                                                                ++p1;
        !          1485:                                                                --str_left;
        !          1486:                                                        }
        !          1487: 
        !          1488:                                                        err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl); 
        !          1489:                                                        if (err != PHP_ICONV_ERR_SUCCESS) {
        !          1490:                                                                goto out;
        !          1491:                                                        }
        !          1492: 
        !          1493:                                                        /* Let's go back and see if there are further
        !          1494:                                                         * encoded words or bare content, and hope they
        !          1495:                                                         * might actually have a valid character set. */
        !          1496:                                                        scan_stat = 12;
        !          1497:                                                        break;
        !          1498:                                                } else {
        !          1499: #if ICONV_SUPPORTS_ERRNO
        !          1500:                                                        if (errno == EINVAL) {
        !          1501:                                                                err = PHP_ICONV_ERR_WRONG_CHARSET;
        !          1502:                                                        } else {
        !          1503:                                                                err = PHP_ICONV_ERR_CONVERTER;
        !          1504:                                                        }
        !          1505: #else
        !          1506:                                                        err = PHP_ICONV_ERR_UNKNOWN;
        !          1507: #endif
        !          1508:                                                        goto out;
        !          1509:                                                }
        !          1510:                                        }
        !          1511:                                }
        !          1512:                                break;
        !          1513: 
        !          1514:                        case 3: /* expecting a encoding scheme specifier */
        !          1515:                                switch (*p1) {
        !          1516:                                        case 'b':
        !          1517:                                        case 'B':
        !          1518:                                                enc_scheme = PHP_ICONV_ENC_SCHEME_BASE64;
        !          1519:                                                scan_stat = 4;
        !          1520:                                                break;
        !          1521: 
        !          1522:                                        case 'q':
        !          1523:                                        case 'Q':
        !          1524:                                                enc_scheme = PHP_ICONV_ENC_SCHEME_QPRINT;
        !          1525:                                                scan_stat = 4;
        !          1526:                                                break;
        !          1527: 
        !          1528:                                        default:
        !          1529:                                                if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
        !          1530:                                                        err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl);
        !          1531:                                                        if (err != PHP_ICONV_ERR_SUCCESS) {
        !          1532:                                                                goto out;
        !          1533:                                                        }
        !          1534:                                                        encoded_word = NULL;
        !          1535:                                                        if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
        !          1536:                                                                scan_stat = 12;
        !          1537:                                                        } else {
        !          1538:                                                                scan_stat = 0;
        !          1539:                                                        }
        !          1540:                                                        break;
        !          1541:                                                } else {
        !          1542:                                                        err = PHP_ICONV_ERR_MALFORMED;
        !          1543:                                                        goto out;
        !          1544:                                                }
        !          1545:                                }
        !          1546:                                break;
        !          1547:                
        !          1548:                        case 4: /* expecting a delimiter */
        !          1549:                                if (*p1 != '?') {
        !          1550:                                        if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
        !          1551:                                                /* pass the entire chunk through the converter */
        !          1552:                                                err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl); 
        !          1553:                                                if (err != PHP_ICONV_ERR_SUCCESS) {
        !          1554:                                                        goto out;
        !          1555:                                                }
        !          1556:                                                encoded_word = NULL;
        !          1557:                                                if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
        !          1558:                                                        scan_stat = 12;
        !          1559:                                                } else {
        !          1560:                                                        scan_stat = 0;
        !          1561:                                                }
        !          1562:                                                break;
        !          1563:                                        } else {
        !          1564:                                                err = PHP_ICONV_ERR_MALFORMED;
        !          1565:                                                goto out;
        !          1566:                                        }
        !          1567:                                }
        !          1568:                                encoded_text = p1 + 1;
        !          1569:                                scan_stat = 5;
        !          1570:                                break;
        !          1571: 
        !          1572:                        case 5: /* expecting an encoded portion */
        !          1573:                                if (*p1 == '?') {
        !          1574:                                        encoded_text_len = (size_t)(p1 - encoded_text);
        !          1575:                                        scan_stat = 6;
        !          1576:                                }
        !          1577:                                break;
        !          1578: 
        !          1579:                        case 7: /* expecting a "\n" character */
        !          1580:                                if (*p1 == '\n') {
        !          1581:                                        scan_stat = 8;
        !          1582:                                } else {
        !          1583:                                        /* bare CR */
        !          1584:                                        _php_iconv_appendc(pretval, '\r', cd_pl);
        !          1585:                                        _php_iconv_appendc(pretval, *p1, cd_pl);
        !          1586:                                        scan_stat = 0;
        !          1587:                                }
        !          1588:                                break;
        !          1589: 
        !          1590:                        case 8: /* checking whether the following line is part of a
        !          1591:                                           folded header */
        !          1592:                                if (*p1 != ' ' && *p1 != '\t') {
        !          1593:                                        --p1;
        !          1594:                                        str_left = 1; /* quit_loop */
        !          1595:                                        break;
        !          1596:                                }
        !          1597:                                if (encoded_word == NULL) {
        !          1598:                                        _php_iconv_appendc(pretval, ' ', cd_pl);
        !          1599:                                }
        !          1600:                                spaces = NULL;
        !          1601:                                scan_stat = 11;
        !          1602:                                break;
        !          1603: 
        !          1604:                        case 6: /* expecting a End-Of-Chunk character "=" */
        !          1605:                                if (*p1 != '=') {
        !          1606:                                        if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
        !          1607:                                                /* pass the entire chunk through the converter */
        !          1608:                                                err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl); 
        !          1609:                                                if (err != PHP_ICONV_ERR_SUCCESS) {
        !          1610:                                                        goto out;
        !          1611:                                                }
        !          1612:                                                encoded_word = NULL;
        !          1613:                                                if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
        !          1614:                                                        scan_stat = 12;
        !          1615:                                                } else {
        !          1616:                                                        scan_stat = 0;
        !          1617:                                                }
        !          1618:                                                break;
        !          1619:                                        } else {
        !          1620:                                                err = PHP_ICONV_ERR_MALFORMED;
        !          1621:                                                goto out;
        !          1622:                                        }
        !          1623:                                }
        !          1624:                                scan_stat = 9;
        !          1625:                                if (str_left == 1) {
        !          1626:                                        eos = 1;
        !          1627:                                } else {
        !          1628:                                        break;
        !          1629:                                }
        !          1630: 
        !          1631:                        case 9: /* choice point, seeing what to do next.*/
        !          1632:                                switch (*p1) {
        !          1633:                                        default:
        !          1634:                                                /* Handle non-RFC-compliant formats
        !          1635:                                                 * 
        !          1636:                                                 * RFC2047 requires the character that comes right
        !          1637:                                                 * after an encoded word (chunk) to be a whitespace,
        !          1638:                                                 * while there are lots of broken implementations that
        !          1639:                                                 * generate such malformed headers that don't fulfill
        !          1640:                                                 * that requirement.
        !          1641:                                                 */ 
        !          1642:                                                if (!eos) { 
        !          1643:                                                        if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
        !          1644:                                                                /* pass the entire chunk through the converter */
        !          1645:                                                                err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl); 
        !          1646:                                                                if (err != PHP_ICONV_ERR_SUCCESS) {
        !          1647:                                                                        goto out;
        !          1648:                                                                }
        !          1649:                                                                scan_stat = 12;
        !          1650:                                                                break;
        !          1651:                                                        }
        !          1652:                                                }
        !          1653:                                                /* break is omitted intentionally */
        !          1654: 
        !          1655:                                        case '\r': case '\n': case ' ': case '\t': {
        !          1656:                                                char *decoded_text;
        !          1657:                                                size_t decoded_text_len;
        !          1658:                                                int dummy;
        !          1659: 
        !          1660:                                                switch (enc_scheme) {
        !          1661:                                                        case PHP_ICONV_ENC_SCHEME_BASE64:
        !          1662:                                                                decoded_text = (char *)php_base64_decode((unsigned char*)encoded_text, (int)encoded_text_len, &dummy);
        !          1663:                                                                decoded_text_len = (size_t)dummy;
        !          1664:                                                                break;
        !          1665: 
        !          1666:                                                        case PHP_ICONV_ENC_SCHEME_QPRINT:
        !          1667:                                                                decoded_text = (char *)php_quot_print_decode((unsigned char*)encoded_text, (int)encoded_text_len, &decoded_text_len, 1);
        !          1668:                                                                break;
        !          1669:                                                        default:
        !          1670:                                                                decoded_text = NULL;
        !          1671:                                                                break;
        !          1672:                                                }
        !          1673: 
        !          1674:                                                if (decoded_text == NULL) {
        !          1675:                                                        if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
        !          1676:                                                                /* pass the entire chunk through the converter */
        !          1677:                                                                err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl); 
        !          1678:                                                                if (err != PHP_ICONV_ERR_SUCCESS) {
        !          1679:                                                                        goto out;
        !          1680:                                                                }
        !          1681:                                                                encoded_word = NULL;
        !          1682:                                                                if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
        !          1683:                                                                        scan_stat = 12;
        !          1684:                                                                } else {
        !          1685:                                                                        scan_stat = 0;
        !          1686:                                                                }
        !          1687:                                                                break;
        !          1688:                                                        } else {
        !          1689:                                                                err = PHP_ICONV_ERR_UNKNOWN;
        !          1690:                                                                goto out;
        !          1691:                                                        }
        !          1692:                                                }
        !          1693: 
        !          1694:                                                err = _php_iconv_appendl(pretval, decoded_text, decoded_text_len, cd);
        !          1695:                                                efree(decoded_text);
        !          1696: 
        !          1697:                                                if (err != PHP_ICONV_ERR_SUCCESS) {
        !          1698:                                                        if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
        !          1699:                                                                /* pass the entire chunk through the converter */
        !          1700:                                                                err = _php_iconv_appendl(pretval, encoded_word, (size_t)(p1 - encoded_word), cd_pl); 
        !          1701:                                                                encoded_word = NULL;
        !          1702:                                                                if (err != PHP_ICONV_ERR_SUCCESS) {
        !          1703:                                                                        break;
        !          1704:                                                                }
        !          1705:                                                        } else {
        !          1706:                                                                goto out;
        !          1707:                                                        }
        !          1708:                                                }
        !          1709: 
        !          1710:                                                if (eos) { /* reached end-of-string. done. */
        !          1711:                                                        scan_stat = 0;
        !          1712:                                                        break;
        !          1713:                                                }
        !          1714: 
        !          1715:                                                switch (*p1) {
        !          1716:                                                        case '\r': /* part of an EOL sequence? */
        !          1717:                                                                scan_stat = 7;
        !          1718:                                                                break;
        !          1719: 
        !          1720:                                                        case '\n':
        !          1721:                                                                scan_stat = 8;
        !          1722:                                                                break;
        !          1723: 
        !          1724:                                                        case '=': /* first letter of an encoded chunk */
        !          1725:                                                                scan_stat = 1;
        !          1726:                                                                break;
        !          1727: 
        !          1728:                                                        case ' ': case '\t': /* medial whitespaces */
        !          1729:                                                                spaces = p1;
        !          1730:                                                                scan_stat = 11;
        !          1731:                                                                break;
        !          1732: 
        !          1733:                                                        default: /* first letter of a non-encoded word */
        !          1734:                                                                _php_iconv_appendc(pretval, *p1, cd_pl);
        !          1735:                                                                scan_stat = 12;
        !          1736:                                                                break;
        !          1737:                                                }
        !          1738:                                        } break;
        !          1739:                                }
        !          1740:                                break;
        !          1741: 
        !          1742:                        case 10: /* expects a language specifier. dismiss it for now */
        !          1743:                                if (*p1 == '?') {
        !          1744:                                        scan_stat = 3;
        !          1745:                                }
        !          1746:                                break;
        !          1747: 
        !          1748:                        case 11: /* expecting a chunk of whitespaces */
        !          1749:                                switch (*p1) {
        !          1750:                                        case '\r': /* part of an EOL sequence? */
        !          1751:                                                scan_stat = 7;
        !          1752:                                                break;
        !          1753: 
        !          1754:                                        case '\n':
        !          1755:                                                scan_stat = 8;  
        !          1756:                                                break;
        !          1757: 
        !          1758:                                        case '=': /* first letter of an encoded chunk */
        !          1759:                                                if (spaces != NULL && encoded_word == NULL) {
        !          1760:                                                        _php_iconv_appendl(pretval, spaces, (size_t)(p1 - spaces), cd_pl);
        !          1761:                                                        spaces = NULL;
        !          1762:                                                }
        !          1763:                                                encoded_word = p1;
        !          1764:                                                scan_stat = 1;
        !          1765:                                                break;
        !          1766: 
        !          1767:                                        case ' ': case '\t':
        !          1768:                                                break;
        !          1769: 
        !          1770:                                        default: /* first letter of a non-encoded word */
        !          1771:                                                if (spaces != NULL) {
        !          1772:                                                        _php_iconv_appendl(pretval, spaces, (size_t)(p1 - spaces), cd_pl);
        !          1773:                                                        spaces = NULL;
        !          1774:                                                }
        !          1775:                                                _php_iconv_appendc(pretval, *p1, cd_pl);
        !          1776:                                                encoded_word = NULL;
        !          1777:                                                if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
        !          1778:                                                        scan_stat = 12;
        !          1779:                                                } else {
        !          1780:                                                        scan_stat = 0;
        !          1781:                                                }
        !          1782:                                                break;
        !          1783:                                }
        !          1784:                                break;
        !          1785: 
        !          1786:                        case 12: /* expecting a non-encoded word */
        !          1787:                                switch (*p1) {
        !          1788:                                        case '\r': /* part of an EOL sequence? */
        !          1789:                                                scan_stat = 7;
        !          1790:                                                break;
        !          1791: 
        !          1792:                                        case '\n':
        !          1793:                                                scan_stat = 8;
        !          1794:                                                break;
        !          1795: 
        !          1796:                                        case ' ': case '\t':
        !          1797:                                                spaces = p1;
        !          1798:                                                scan_stat = 11;
        !          1799:                                                break;
        !          1800: 
        !          1801:                                        case '=': /* first letter of an encoded chunk */
        !          1802:                                                if (!(mode & PHP_ICONV_MIME_DECODE_STRICT)) {
        !          1803:                                                        encoded_word = p1;
        !          1804:                                                        scan_stat = 1;
        !          1805:                                                        break;
        !          1806:                                                }
        !          1807:                                                /* break is omitted intentionally */
        !          1808: 
        !          1809:                                        default:
        !          1810:                                                _php_iconv_appendc(pretval, *p1, cd_pl);
        !          1811:                                                break;
        !          1812:                                }
        !          1813:                                break;
        !          1814:                }
        !          1815:        }
        !          1816:        switch (scan_stat) {
        !          1817:                case 0: case 8: case 11: case 12:
        !          1818:                        break;
        !          1819:                default:
        !          1820:                        if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
        !          1821:                                if (scan_stat == 1) {
        !          1822:                                        _php_iconv_appendc(pretval, '=', cd_pl);
        !          1823:                                }
        !          1824:                                err = PHP_ICONV_ERR_SUCCESS;
        !          1825:                        } else {
        !          1826:                                err = PHP_ICONV_ERR_MALFORMED;
        !          1827:                                goto out;
        !          1828:                        }
        !          1829:        }
        !          1830: 
        !          1831:        if (next_pos != NULL) {
        !          1832:                *next_pos = p1;
        !          1833:        }
        !          1834: 
        !          1835:        smart_str_0(pretval);
        !          1836: out:
        !          1837:        if (cd != (iconv_t)(-1)) {
        !          1838:                iconv_close(cd);
        !          1839:        }
        !          1840:        if (cd_pl != (iconv_t)(-1)) {
        !          1841:                iconv_close(cd_pl);
        !          1842:        }
        !          1843:        return err;
        !          1844: }
        !          1845: /* }}} */
        !          1846: 
        !          1847: /* {{{ php_iconv_show_error() */
        !          1848: static void _php_iconv_show_error(php_iconv_err_t err, const char *out_charset, const char *in_charset TSRMLS_DC)
        !          1849: {
        !          1850:        switch (err) {
        !          1851:                case PHP_ICONV_ERR_SUCCESS:
        !          1852:                        break;
        !          1853: 
        !          1854:                case PHP_ICONV_ERR_CONVERTER:
        !          1855:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot open converter");
        !          1856:                        break;
        !          1857: 
        !          1858:                case PHP_ICONV_ERR_WRONG_CHARSET:
        !          1859:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong charset, conversion from `%s' to `%s' is not allowed",
        !          1860:                                  in_charset, out_charset);
        !          1861:                        break;
        !          1862: 
        !          1863:                case PHP_ICONV_ERR_ILLEGAL_CHAR:
        !          1864:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected an incomplete multibyte character in input string");
        !          1865:                        break;
        !          1866: 
        !          1867:                case PHP_ICONV_ERR_ILLEGAL_SEQ:
        !          1868:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected an illegal character in input string");
        !          1869:                        break;
        !          1870: 
        !          1871:                case PHP_ICONV_ERR_TOO_BIG:
        !          1872:                        /* should not happen */
        !          1873:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Buffer length exceeded");
        !          1874:                        break;
        !          1875: 
        !          1876:                case PHP_ICONV_ERR_MALFORMED:
        !          1877:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Malformed string");
        !          1878:                        break;
        !          1879: 
        !          1880:                default:
        !          1881:                        /* other error */
        !          1882:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unknown error (%d)", errno);
        !          1883:                        break;
        !          1884:        }
        !          1885: }
        !          1886: /* }}} */
        !          1887: 
        !          1888: /* {{{ proto int iconv_strlen(string str [, string charset])
        !          1889:    Returns the character count of str */
        !          1890: PHP_FUNCTION(iconv_strlen)
        !          1891: {
        !          1892:        char *charset = ICONVG(internal_encoding);
        !          1893:        int charset_len = 0;
        !          1894:        char *str;
        !          1895:        int str_len; 
        !          1896: 
        !          1897:        php_iconv_err_t err;
        !          1898: 
        !          1899:        unsigned int retval;
        !          1900: 
        !          1901:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s",
        !          1902:                &str, &str_len, &charset, &charset_len) == FAILURE) {
        !          1903:                RETURN_FALSE;
        !          1904:        }
        !          1905: 
        !          1906:        if (charset_len >= ICONV_CSNMAXLEN) {
        !          1907:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
        !          1908:                RETURN_FALSE;
        !          1909:        }
        !          1910: 
        !          1911:        err = _php_iconv_strlen(&retval, str, str_len, charset); 
        !          1912:        _php_iconv_show_error(err, GENERIC_SUPERSET_NAME, charset TSRMLS_CC);
        !          1913:        if (err == PHP_ICONV_ERR_SUCCESS) {
        !          1914:                RETVAL_LONG(retval);
        !          1915:        } else {
        !          1916:                RETVAL_FALSE;
        !          1917:        }
        !          1918: }
        !          1919: /* }}} */
        !          1920: 
        !          1921: /* {{{ proto string iconv_substr(string str, int offset, [int length, string charset])
        !          1922:    Returns specified part of a string */
        !          1923: PHP_FUNCTION(iconv_substr)
        !          1924: {
        !          1925:        char *charset = ICONVG(internal_encoding);
        !          1926:        int charset_len = 0;
        !          1927:        char *str;
        !          1928:        int str_len; 
        !          1929:        long offset, length = 0;
        !          1930: 
        !          1931:        php_iconv_err_t err;
        !          1932: 
        !          1933:        smart_str retval = {0};
        !          1934: 
        !          1935:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|ls",
        !          1936:                &str, &str_len, &offset, &length,
        !          1937:                &charset, &charset_len) == FAILURE) {
        !          1938:                RETURN_FALSE;
        !          1939:        }
        !          1940: 
        !          1941:        if (charset_len >= ICONV_CSNMAXLEN) {
        !          1942:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
        !          1943:                RETURN_FALSE;
        !          1944:        }
        !          1945: 
        !          1946:        if (ZEND_NUM_ARGS() < 3) {
        !          1947:                length = str_len; 
        !          1948:        }
        !          1949: 
        !          1950:        err = _php_iconv_substr(&retval, str, str_len, offset, length, charset); 
        !          1951:        _php_iconv_show_error(err, GENERIC_SUPERSET_NAME, charset TSRMLS_CC);
        !          1952: 
        !          1953:        if (err == PHP_ICONV_ERR_SUCCESS && str != NULL && retval.c != NULL) {
        !          1954:                RETURN_STRINGL(retval.c, retval.len, 0);
        !          1955:        }
        !          1956:        smart_str_free(&retval);
        !          1957:        RETURN_FALSE;
        !          1958: }
        !          1959: /* }}} */
        !          1960: 
        !          1961: /* {{{ proto int iconv_strpos(string haystack, string needle [, int offset [, string charset]])
        !          1962:    Finds position of first occurrence of needle within part of haystack beginning with offset */
        !          1963: PHP_FUNCTION(iconv_strpos)
        !          1964: {
        !          1965:        char *charset = ICONVG(internal_encoding);
        !          1966:        int charset_len = 0;
        !          1967:        char *haystk;
        !          1968:        int haystk_len; 
        !          1969:        char *ndl;
        !          1970:        int ndl_len;
        !          1971:        long offset = 0;
        !          1972: 
        !          1973:        php_iconv_err_t err;
        !          1974: 
        !          1975:        unsigned int retval;
        !          1976: 
        !          1977:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ls",
        !          1978:                &haystk, &haystk_len, &ndl, &ndl_len,
        !          1979:                &offset, &charset, &charset_len) == FAILURE) {
        !          1980:                RETURN_FALSE;
        !          1981:        }
        !          1982: 
        !          1983:        if (charset_len >= ICONV_CSNMAXLEN) {
        !          1984:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
        !          1985:                RETURN_FALSE;
        !          1986:        }
        !          1987: 
        !          1988:        if (offset < 0) {
        !          1989:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset not contained in string.");
        !          1990:                RETURN_FALSE;
        !          1991:        }
        !          1992: 
        !          1993:        if (ndl_len < 1) {
        !          1994:                RETURN_FALSE;
        !          1995:        }
        !          1996: 
        !          1997:        err = _php_iconv_strpos(&retval, haystk, haystk_len, ndl, ndl_len,
        !          1998:                                offset, charset); 
        !          1999:        _php_iconv_show_error(err, GENERIC_SUPERSET_NAME, charset TSRMLS_CC);
        !          2000: 
        !          2001:        if (err == PHP_ICONV_ERR_SUCCESS && retval != (unsigned int)-1) {
        !          2002:                RETVAL_LONG((long)retval);
        !          2003:        } else {
        !          2004:                RETVAL_FALSE;
        !          2005:        }
        !          2006: }
        !          2007: /* }}} */
        !          2008: 
        !          2009: /* {{{ proto int iconv_strrpos(string haystack, string needle [, string charset])
        !          2010:    Finds position of last occurrence of needle within part of haystack beginning with offset */
        !          2011: PHP_FUNCTION(iconv_strrpos)
        !          2012: {
        !          2013:        char *charset = ICONVG(internal_encoding);
        !          2014:        int charset_len = 0;
        !          2015:        char *haystk;
        !          2016:        int haystk_len; 
        !          2017:        char *ndl;
        !          2018:        int ndl_len;
        !          2019: 
        !          2020:        php_iconv_err_t err;
        !          2021: 
        !          2022:        unsigned int retval;
        !          2023: 
        !          2024:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s",
        !          2025:                &haystk, &haystk_len, &ndl, &ndl_len,
        !          2026:                &charset, &charset_len) == FAILURE) {
        !          2027:                RETURN_FALSE;
        !          2028:        }
        !          2029: 
        !          2030:        if (ndl_len < 1) {
        !          2031:                RETURN_FALSE;
        !          2032:        }
        !          2033: 
        !          2034:        if (charset_len >= ICONV_CSNMAXLEN) {
        !          2035:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
        !          2036:                RETURN_FALSE;
        !          2037:        }
        !          2038: 
        !          2039:        err = _php_iconv_strpos(&retval, haystk, haystk_len, ndl, ndl_len,
        !          2040:                                -1, charset); 
        !          2041:        _php_iconv_show_error(err, GENERIC_SUPERSET_NAME, charset TSRMLS_CC);
        !          2042: 
        !          2043:        if (err == PHP_ICONV_ERR_SUCCESS && retval != (unsigned int)-1) {
        !          2044:                RETVAL_LONG((long)retval);
        !          2045:        } else {
        !          2046:                RETVAL_FALSE;
        !          2047:        }
        !          2048: }
        !          2049: /* }}} */
        !          2050: 
        !          2051: /* {{{ proto string iconv_mime_encode(string field_name, string field_value [, array preference])
        !          2052:    Composes a mime header field with field_name and field_value in a specified scheme */
        !          2053: PHP_FUNCTION(iconv_mime_encode)
        !          2054: {
        !          2055:        const char *field_name = NULL;
        !          2056:        int field_name_len;
        !          2057:        const char *field_value = NULL;
        !          2058:        int field_value_len;
        !          2059:        zval *pref = NULL;
        !          2060:        zval tmp_zv, *tmp_zv_p = NULL;
        !          2061:        smart_str retval = {0};
        !          2062:        php_iconv_err_t err;
        !          2063: 
        !          2064:        const char *in_charset = ICONVG(internal_encoding);
        !          2065:        const char *out_charset = in_charset;
        !          2066:        long line_len = 76;
        !          2067:        const char *lfchars = "\r\n";
        !          2068:        php_iconv_enc_scheme_t scheme_id = PHP_ICONV_ENC_SCHEME_BASE64;
        !          2069: 
        !          2070:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a",
        !          2071:                &field_name, &field_name_len, &field_value, &field_value_len,
        !          2072:                &pref) == FAILURE) {
        !          2073: 
        !          2074:                RETURN_FALSE;
        !          2075:        }
        !          2076: 
        !          2077:        if (pref != NULL) {
        !          2078:                zval **ppval;
        !          2079: 
        !          2080:                if (zend_hash_find(Z_ARRVAL_P(pref), "scheme", sizeof("scheme"), (void **)&ppval) == SUCCESS) {
        !          2081:                        if (Z_TYPE_PP(ppval) == IS_STRING && Z_STRLEN_PP(ppval) > 0) {
        !          2082:                                switch (Z_STRVAL_PP(ppval)[0]) {
        !          2083:                                        case 'B': case 'b':
        !          2084:                                                scheme_id = PHP_ICONV_ENC_SCHEME_BASE64;
        !          2085:                                                break;
        !          2086: 
        !          2087:                                        case 'Q': case 'q':
        !          2088:                                                scheme_id = PHP_ICONV_ENC_SCHEME_QPRINT;
        !          2089:                                                break;
        !          2090:                                }
        !          2091:                        }
        !          2092:                }
        !          2093: 
        !          2094:                if (zend_hash_find(Z_ARRVAL_P(pref), "input-charset", sizeof("input-charset"), (void **)&ppval) == SUCCESS) {
        !          2095:                        if (Z_STRLEN_PP(ppval) >= ICONV_CSNMAXLEN) {
        !          2096:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
        !          2097:                                RETURN_FALSE;
        !          2098:                        }
        !          2099: 
        !          2100:                        if (Z_TYPE_PP(ppval) == IS_STRING && Z_STRLEN_PP(ppval) > 0) {
        !          2101:                                in_charset = Z_STRVAL_PP(ppval);
        !          2102:                        }
        !          2103:                }
        !          2104: 
        !          2105: 
        !          2106:                if (zend_hash_find(Z_ARRVAL_P(pref), "output-charset", sizeof("output-charset"), (void **)&ppval) == SUCCESS) {
        !          2107:                        if (Z_STRLEN_PP(ppval) >= ICONV_CSNMAXLEN) {
        !          2108:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
        !          2109:                                RETURN_FALSE;
        !          2110:                        }
        !          2111: 
        !          2112:                        if (Z_TYPE_PP(ppval) == IS_STRING && Z_STRLEN_PP(ppval) > 0) {
        !          2113:                                out_charset = Z_STRVAL_PP(ppval);
        !          2114:                        }
        !          2115:                }
        !          2116: 
        !          2117:                if (zend_hash_find(Z_ARRVAL_P(pref), "line-length", sizeof("line-length"), (void **)&ppval) == SUCCESS) {
        !          2118:                        zval val, *pval = *ppval;
        !          2119: 
        !          2120:                        if (Z_TYPE_P(pval) != IS_LONG) {
        !          2121:                                val = *pval;
        !          2122:                                zval_copy_ctor(&val);
        !          2123:                                convert_to_long(&val);
        !          2124:                                pval = &val;
        !          2125:                        }
        !          2126: 
        !          2127:                        line_len = Z_LVAL_P(pval);
        !          2128: 
        !          2129:                        if (pval == &val) {
        !          2130:                                zval_dtor(&val);
        !          2131:                        }
        !          2132:                }
        !          2133: 
        !          2134:                if (zend_hash_find(Z_ARRVAL_P(pref), "line-break-chars", sizeof("line-break-chars"), (void **)&ppval) == SUCCESS) {
        !          2135:                        if (Z_TYPE_PP(ppval) != IS_STRING) {
        !          2136:                                tmp_zv = **ppval;
        !          2137:                                zval_copy_ctor(&tmp_zv);
        !          2138:                                convert_to_string(&tmp_zv);
        !          2139: 
        !          2140:                                lfchars = Z_STRVAL(tmp_zv);
        !          2141: 
        !          2142:                                tmp_zv_p = &tmp_zv;
        !          2143:                        } else {
        !          2144:                                lfchars = Z_STRVAL_PP(ppval);
        !          2145:                        }
        !          2146:                }
        !          2147:        }
        !          2148: 
        !          2149:        err = _php_iconv_mime_encode(&retval, field_name, field_name_len,
        !          2150:                field_value, field_value_len, line_len, lfchars, scheme_id,
        !          2151:                out_charset, in_charset);
        !          2152:        _php_iconv_show_error(err, out_charset, in_charset TSRMLS_CC);
        !          2153: 
        !          2154:        if (err == PHP_ICONV_ERR_SUCCESS) {
        !          2155:                if (retval.c != NULL) {
        !          2156:                        RETVAL_STRINGL(retval.c, retval.len, 0);
        !          2157:                } else {
        !          2158:                        RETVAL_EMPTY_STRING();
        !          2159:                }
        !          2160:        } else {
        !          2161:                smart_str_free(&retval);
        !          2162:                RETVAL_FALSE;
        !          2163:        }
        !          2164: 
        !          2165:        if (tmp_zv_p != NULL) {
        !          2166:                zval_dtor(tmp_zv_p);
        !          2167:        }
        !          2168: }
        !          2169: /* }}} */
        !          2170: 
        !          2171: /* {{{ proto string iconv_mime_decode(string encoded_string [, int mode, string charset])
        !          2172:    Decodes a mime header field */
        !          2173: PHP_FUNCTION(iconv_mime_decode)
        !          2174: {
        !          2175:        char *encoded_str;
        !          2176:        int encoded_str_len;
        !          2177:        char *charset = ICONVG(internal_encoding);
        !          2178:        int charset_len = 0;
        !          2179:        long mode = 0;
        !          2180:        
        !          2181:        smart_str retval = {0};
        !          2182: 
        !          2183:        php_iconv_err_t err;
        !          2184: 
        !          2185:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls",
        !          2186:                &encoded_str, &encoded_str_len, &mode, &charset, &charset_len) == FAILURE) {
        !          2187: 
        !          2188:                RETURN_FALSE;
        !          2189:        }
        !          2190: 
        !          2191:        if (charset_len >= ICONV_CSNMAXLEN) {
        !          2192:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
        !          2193:                RETURN_FALSE;
        !          2194:        }
        !          2195: 
        !          2196:        err = _php_iconv_mime_decode(&retval, encoded_str, encoded_str_len, charset, NULL, mode);
        !          2197:        _php_iconv_show_error(err, charset, "???" TSRMLS_CC);
        !          2198: 
        !          2199:        if (err == PHP_ICONV_ERR_SUCCESS) {
        !          2200:                if (retval.c != NULL) {
        !          2201:                        RETVAL_STRINGL(retval.c, retval.len, 0);
        !          2202:                } else {
        !          2203:                        RETVAL_EMPTY_STRING();
        !          2204:                }
        !          2205:        } else {
        !          2206:                smart_str_free(&retval);
        !          2207:                RETVAL_FALSE;
        !          2208:        }
        !          2209: }
        !          2210: /* }}} */
        !          2211: 
        !          2212: /* {{{ proto array iconv_mime_decode_headers(string headers [, int mode, string charset])
        !          2213:    Decodes multiple mime header fields */
        !          2214: PHP_FUNCTION(iconv_mime_decode_headers)
        !          2215: {
        !          2216:        const char *encoded_str;
        !          2217:        int encoded_str_len;
        !          2218:        char *charset = ICONVG(internal_encoding);
        !          2219:        int charset_len = 0;
        !          2220:        long mode = 0;
        !          2221:        
        !          2222:        php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS;
        !          2223: 
        !          2224:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls",
        !          2225:                &encoded_str, &encoded_str_len, &mode, &charset, &charset_len) == FAILURE) {
        !          2226: 
        !          2227:                RETURN_FALSE;
        !          2228:        }
        !          2229: 
        !          2230:        if (charset_len >= ICONV_CSNMAXLEN) {
        !          2231:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
        !          2232:                RETURN_FALSE;
        !          2233:        }
        !          2234: 
        !          2235:        array_init(return_value);
        !          2236: 
        !          2237:        while (encoded_str_len > 0) {
        !          2238:                smart_str decoded_header = {0};
        !          2239:                char *header_name = NULL;
        !          2240:                size_t header_name_len = 0;
        !          2241:                char *header_value = NULL;
        !          2242:                size_t header_value_len = 0;
        !          2243:                char *p, *limit;
        !          2244:                const char *next_pos;
        !          2245: 
        !          2246:                if (PHP_ICONV_ERR_SUCCESS != (err = _php_iconv_mime_decode(&decoded_header, encoded_str, encoded_str_len, charset, &next_pos, mode))) {
        !          2247:                        smart_str_free(&decoded_header);
        !          2248:                        break;
        !          2249:                }
        !          2250: 
        !          2251:                if (decoded_header.c == NULL) {
        !          2252:                        break;
        !          2253:                }
        !          2254: 
        !          2255:                limit = decoded_header.c + decoded_header.len;
        !          2256:                for (p = decoded_header.c; p < limit; p++) {
        !          2257:                        if (*p == ':') {
        !          2258:                                *p = '\0';
        !          2259:                                header_name = decoded_header.c;
        !          2260:                                header_name_len = (p - decoded_header.c) + 1;
        !          2261: 
        !          2262:                                while (++p < limit) {
        !          2263:                                        if (*p != ' ' && *p != '\t') {
        !          2264:                                                break;
        !          2265:                                        }
        !          2266:                                }
        !          2267: 
        !          2268:                                header_value = p;
        !          2269:                                header_value_len = limit - p;
        !          2270: 
        !          2271:                                break;
        !          2272:                        }
        !          2273:                }
        !          2274: 
        !          2275:                if (header_name != NULL) {
        !          2276:                        zval **elem, *new_elem;
        !          2277: 
        !          2278:                        if (zend_hash_find(Z_ARRVAL_P(return_value), header_name, header_name_len, (void **)&elem) == SUCCESS) {
        !          2279:                                if (Z_TYPE_PP(elem) != IS_ARRAY) {
        !          2280:                                        MAKE_STD_ZVAL(new_elem);
        !          2281:                                        array_init(new_elem);
        !          2282: 
        !          2283:                                        Z_ADDREF_PP(elem);
        !          2284:                                        add_next_index_zval(new_elem, *elem);
        !          2285: 
        !          2286:                                        zend_hash_update(Z_ARRVAL_P(return_value), header_name, header_name_len, (void *)&new_elem, sizeof(new_elem), NULL);
        !          2287: 
        !          2288:                                        elem = &new_elem;
        !          2289:                                }       
        !          2290:                                add_next_index_stringl(*elem, header_value, header_value_len, 1);
        !          2291:                        } else {
        !          2292:                                add_assoc_stringl_ex(return_value, header_name, header_name_len, header_value, header_value_len, 1);
        !          2293:                        }
        !          2294:                }
        !          2295:                encoded_str_len -= next_pos - encoded_str;
        !          2296:                encoded_str = next_pos; 
        !          2297: 
        !          2298:                smart_str_free(&decoded_header);
        !          2299:        }
        !          2300: 
        !          2301:        if (err != PHP_ICONV_ERR_SUCCESS) {
        !          2302:                _php_iconv_show_error(err, charset, "???" TSRMLS_CC);
        !          2303:                zval_dtor(return_value);
        !          2304:                RETVAL_FALSE;
        !          2305:        }
        !          2306: }
        !          2307: /* }}} */
        !          2308: 
        !          2309: /* {{{ proto string iconv(string in_charset, string out_charset, string str)
        !          2310:    Returns str converted to the out_charset character set */
        !          2311: PHP_NAMED_FUNCTION(php_if_iconv)
        !          2312: {
        !          2313:        char *in_charset, *out_charset, *in_buffer, *out_buffer;
        !          2314:        size_t out_len;
        !          2315:        int in_charset_len = 0, out_charset_len = 0, in_buffer_len;
        !          2316:        php_iconv_err_t err;
        !          2317:        
        !          2318:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss",
        !          2319:                &in_charset, &in_charset_len, &out_charset, &out_charset_len, &in_buffer, &in_buffer_len) == FAILURE)
        !          2320:                return;
        !          2321: 
        !          2322:        if (in_charset_len >= ICONV_CSNMAXLEN || out_charset_len >= ICONV_CSNMAXLEN) {
        !          2323:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
        !          2324:                RETURN_FALSE;
        !          2325:        }
        !          2326: 
        !          2327:        err = php_iconv_string(in_buffer, (size_t)in_buffer_len,
        !          2328:                &out_buffer, &out_len, out_charset, in_charset);
        !          2329:        _php_iconv_show_error(err, out_charset, in_charset TSRMLS_CC); 
        !          2330:        if (out_buffer != NULL) {
        !          2331:                RETVAL_STRINGL(out_buffer, out_len, 0);
        !          2332:        } else {
        !          2333:                RETURN_FALSE;
        !          2334:        }
        !          2335: }
        !          2336: /* }}} */
        !          2337: 
        !          2338: /* {{{ proto string ob_iconv_handler(string contents, int status)
        !          2339:    Returns str in output buffer converted to the iconv.output_encoding character set */
        !          2340: PHP_FUNCTION(ob_iconv_handler)
        !          2341: {
        !          2342:        char *out_buffer, *content_type, *mimetype = NULL, *s;
        !          2343:        zval *zv_string;
        !          2344:        size_t out_len;
        !          2345:        int mimetype_alloced  = 0;
        !          2346:        long status;
        !          2347: 
        !          2348:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zl", &zv_string, &status) == FAILURE)
        !          2349:                return;
        !          2350: 
        !          2351:        convert_to_string(zv_string);
        !          2352: 
        !          2353:        if (SG(sapi_headers).mimetype && 
        !          2354:                strncasecmp(SG(sapi_headers).mimetype, "text/", 5) == 0) {
        !          2355:                if ((s = strchr(SG(sapi_headers).mimetype,';')) == NULL){
        !          2356:                        mimetype = SG(sapi_headers).mimetype;
        !          2357:                } else {
        !          2358:                        mimetype = estrndup(SG(sapi_headers).mimetype, s-SG(sapi_headers).mimetype);
        !          2359:                        mimetype_alloced = 1;
        !          2360:                }
        !          2361:        } else if (SG(sapi_headers).send_default_content_type) {
        !          2362:                mimetype =(SG(default_mimetype) ? SG(default_mimetype) : SAPI_DEFAULT_MIMETYPE);
        !          2363:        }
        !          2364:        if (mimetype != NULL) {
        !          2365:                php_iconv_err_t err = php_iconv_string(Z_STRVAL_P(zv_string),
        !          2366:                                Z_STRLEN_P(zv_string), &out_buffer, &out_len,
        !          2367:                                ICONVG(output_encoding), ICONVG(internal_encoding));
        !          2368:                _php_iconv_show_error(err, ICONVG(output_encoding), ICONVG(internal_encoding) TSRMLS_CC);
        !          2369:                if (out_buffer != NULL) {
        !          2370:                        int len;
        !          2371:                        char *p = strstr(ICONVG(output_encoding), "//"); 
        !          2372:                        if (p) {
        !          2373:                                len = spprintf(&content_type, 0, "Content-Type:%s; charset=%.*s", mimetype, (int)(p - ICONVG(output_encoding)), ICONVG(output_encoding));
        !          2374:                        } else {
        !          2375:                                len = spprintf(&content_type, 0, "Content-Type:%s; charset=%s", mimetype, ICONVG(output_encoding));
        !          2376:                        }
        !          2377:                        if (content_type && sapi_add_header(content_type, len, 0) != FAILURE) {
        !          2378:                                SG(sapi_headers).send_default_content_type = 0;
        !          2379:                        }
        !          2380:                        if (mimetype_alloced) {
        !          2381:                                efree(mimetype);
        !          2382:                        }
        !          2383:                        RETURN_STRINGL(out_buffer, out_len, 0);
        !          2384:                }
        !          2385:                if (mimetype_alloced) {
        !          2386:                        efree(mimetype);
        !          2387:                }
        !          2388:        }
        !          2389: 
        !          2390:        zval_dtor(return_value);
        !          2391:        *return_value = *zv_string;
        !          2392:        zval_copy_ctor(return_value);
        !          2393: }
        !          2394: /* }}} */
        !          2395: 
        !          2396: /* {{{ proto bool iconv_set_encoding(string type, string charset)
        !          2397:    Sets internal encoding and output encoding for ob_iconv_handler() */
        !          2398: PHP_FUNCTION(iconv_set_encoding)
        !          2399: {
        !          2400:        char *type, *charset;
        !          2401:        int type_len, charset_len =0, retval;
        !          2402: 
        !          2403:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &type, &type_len, &charset, &charset_len) == FAILURE)
        !          2404:                return;
        !          2405: 
        !          2406:        if (charset_len >= ICONV_CSNMAXLEN) {
        !          2407:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
        !          2408:                RETURN_FALSE;
        !          2409:        }
        !          2410: 
        !          2411:        if(!strcasecmp("input_encoding", type)) {
        !          2412:                retval = zend_alter_ini_entry("iconv.input_encoding", sizeof("iconv.input_encoding"), charset, charset_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
        !          2413:        } else if(!strcasecmp("output_encoding", type)) {
        !          2414:                retval = zend_alter_ini_entry("iconv.output_encoding", sizeof("iconv.output_encoding"), charset, charset_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
        !          2415:        } else if(!strcasecmp("internal_encoding", type)) {
        !          2416:                retval = zend_alter_ini_entry("iconv.internal_encoding", sizeof("iconv.internal_encoding"), charset, charset_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
        !          2417:        } else {
        !          2418:                RETURN_FALSE;
        !          2419:        }
        !          2420: 
        !          2421:        if (retval == SUCCESS) {
        !          2422:                RETURN_TRUE;
        !          2423:        } else {
        !          2424:                RETURN_FALSE;
        !          2425:        }
        !          2426: }
        !          2427: /* }}} */
        !          2428: 
        !          2429: /* {{{ proto mixed iconv_get_encoding([string type])
        !          2430:    Get internal encoding and output encoding for ob_iconv_handler() */
        !          2431: PHP_FUNCTION(iconv_get_encoding)
        !          2432: {
        !          2433:        char *type = "all";
        !          2434:        int type_len = sizeof("all")-1;
        !          2435: 
        !          2436:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &type, &type_len) == FAILURE)
        !          2437:                return;
        !          2438: 
        !          2439:        if (!strcasecmp("all", type)) {
        !          2440:                array_init(return_value);
        !          2441:                add_assoc_string(return_value, "input_encoding",    ICONVG(input_encoding), 1);
        !          2442:                add_assoc_string(return_value, "output_encoding",   ICONVG(output_encoding), 1);
        !          2443:                add_assoc_string(return_value, "internal_encoding", ICONVG(internal_encoding), 1);
        !          2444:        } else if (!strcasecmp("input_encoding", type)) {
        !          2445:                RETVAL_STRING(ICONVG(input_encoding), 1);
        !          2446:        } else if (!strcasecmp("output_encoding", type)) {
        !          2447:                RETVAL_STRING(ICONVG(output_encoding), 1);
        !          2448:        } else if (!strcasecmp("internal_encoding", type)) {
        !          2449:                RETVAL_STRING(ICONVG(internal_encoding), 1);
        !          2450:        } else {
        !          2451:                RETURN_FALSE;
        !          2452:        }
        !          2453: 
        !          2454: }
        !          2455: /* }}} */
        !          2456: 
        !          2457: /* {{{ iconv stream filter */
        !          2458: typedef struct _php_iconv_stream_filter {
        !          2459:        iconv_t cd;
        !          2460:        int persistent;
        !          2461:        char *to_charset;
        !          2462:        size_t to_charset_len;
        !          2463:        char *from_charset;
        !          2464:        size_t from_charset_len;
        !          2465:        char stub[128];
        !          2466:        size_t stub_len;
        !          2467: } php_iconv_stream_filter;
        !          2468: /* }}} iconv stream filter */
        !          2469: 
        !          2470: /* {{{ php_iconv_stream_filter_dtor */
        !          2471: static void php_iconv_stream_filter_dtor(php_iconv_stream_filter *self)
        !          2472: {
        !          2473:        iconv_close(self->cd);
        !          2474:        pefree(self->to_charset, self->persistent);
        !          2475:        pefree(self->from_charset, self->persistent);
        !          2476: }
        !          2477: /* }}} */
        !          2478: 
        !          2479: /* {{{ php_iconv_stream_filter_ctor() */
        !          2480: static php_iconv_err_t php_iconv_stream_filter_ctor(php_iconv_stream_filter *self,
        !          2481:                const char *to_charset, size_t to_charset_len,
        !          2482:                const char *from_charset, size_t from_charset_len, int persistent)
        !          2483: {
        !          2484:        if (NULL == (self->to_charset = pemalloc(to_charset_len + 1, persistent))) {
        !          2485:                return PHP_ICONV_ERR_ALLOC;
        !          2486:        }
        !          2487:        self->to_charset_len = to_charset_len;
        !          2488:        if (NULL == (self->from_charset = pemalloc(from_charset_len + 1, persistent))) {
        !          2489:                pefree(self->to_charset, persistent);
        !          2490:                return PHP_ICONV_ERR_ALLOC;
        !          2491:        }
        !          2492:        self->from_charset_len = from_charset_len;
        !          2493: 
        !          2494:        memcpy(self->to_charset, to_charset, to_charset_len);
        !          2495:        self->to_charset[to_charset_len] = '\0';
        !          2496:        memcpy(self->from_charset, from_charset, from_charset_len);
        !          2497:        self->from_charset[from_charset_len] = '\0';
        !          2498: 
        !          2499:        if ((iconv_t)-1 == (self->cd = iconv_open(self->to_charset, self->from_charset))) {
        !          2500:                pefree(self->from_charset, persistent);
        !          2501:                pefree(self->to_charset, persistent);
        !          2502:                return PHP_ICONV_ERR_UNKNOWN;
        !          2503:        }
        !          2504:        self->persistent = persistent;
        !          2505:        self->stub_len = 0;
        !          2506:        return PHP_ICONV_ERR_SUCCESS;
        !          2507: }
        !          2508: /* }}} */
        !          2509: 
        !          2510: /* {{{ php_iconv_stream_filter_append_bucket */
        !          2511: static int php_iconv_stream_filter_append_bucket(
        !          2512:                php_iconv_stream_filter *self,
        !          2513:                php_stream *stream, php_stream_filter *filter,
        !          2514:                php_stream_bucket_brigade *buckets_out,
        !          2515:                const char *ps, size_t buf_len, size_t *consumed,
        !          2516:                int persistent TSRMLS_DC)
        !          2517: {
        !          2518:        php_stream_bucket *new_bucket;
        !          2519:        char *out_buf = NULL;
        !          2520:        size_t out_buf_size;
        !          2521:        char *pd, *pt;
        !          2522:        size_t ocnt, prev_ocnt, icnt, tcnt;
        !          2523:        size_t initial_out_buf_size;
        !          2524:        
        !          2525:        if (ps == NULL) {
        !          2526:                initial_out_buf_size = 64;
        !          2527:                icnt = 1;
        !          2528:        } else {
        !          2529:                initial_out_buf_size = buf_len;
        !          2530:                icnt = buf_len;
        !          2531:        }
        !          2532: 
        !          2533:        out_buf_size = ocnt = prev_ocnt = initial_out_buf_size; 
        !          2534:        if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) {
        !          2535:                return FAILURE;
        !          2536:        }
        !          2537: 
        !          2538:        pd = out_buf;
        !          2539: 
        !          2540:        if (self->stub_len > 0) {
        !          2541:                pt = self->stub;
        !          2542:                tcnt = self->stub_len;
        !          2543: 
        !          2544:                while (tcnt > 0) {
        !          2545:                        if (iconv(self->cd, &pt, &tcnt, &pd, &ocnt) == (size_t)-1) {
        !          2546: #if ICONV_SUPPORTS_ERRNO
        !          2547:                                switch (errno) {
        !          2548:                                        case EILSEQ:
        !          2549:                                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): invalid multibyte sequence", self->from_charset, self->to_charset);
        !          2550:                                                goto out_failure;
        !          2551: 
        !          2552:                                        case EINVAL:
        !          2553:                                                if (ps != NULL) {
        !          2554:                                                        if (icnt > 0) {
        !          2555:                                                                if (self->stub_len >= sizeof(self->stub)) {
        !          2556:                                                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): insufficient buffer", self->from_charset, self->to_charset);
        !          2557:                                                                        goto out_failure;
        !          2558:                                                                }
        !          2559:                                                                self->stub[self->stub_len++] = *(ps++);
        !          2560:                                                                icnt--;
        !          2561:                                                                pt = self->stub;
        !          2562:                                                                tcnt = self->stub_len;
        !          2563:                                                        } else {
        !          2564:                                                                tcnt = 0;
        !          2565:                                                                break;
        !          2566:                                                        }
        !          2567:                                                }
        !          2568:                                                break;
        !          2569: 
        !          2570:                                        case E2BIG: {
        !          2571:                                                char *new_out_buf;
        !          2572:                                                size_t new_out_buf_size;
        !          2573: 
        !          2574:                                                new_out_buf_size = out_buf_size << 1;
        !          2575: 
        !          2576:                                                if (new_out_buf_size < out_buf_size) {
        !          2577:                                                        /* whoa! no bigger buckets are sold anywhere... */
        !          2578:                                                        if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
        !          2579:                                                                goto out_failure;
        !          2580:                                                        }
        !          2581: 
        !          2582:                                                        php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
        !          2583: 
        !          2584:                                                        out_buf_size = ocnt = initial_out_buf_size;
        !          2585:                                                        if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) {
        !          2586:                                                                return FAILURE;
        !          2587:                                                        }
        !          2588:                                                        pd = out_buf;
        !          2589:                                                } else {
        !          2590:                                                        if (NULL == (new_out_buf = perealloc(out_buf, new_out_buf_size, persistent))) {
        !          2591:                                                                if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
        !          2592:                                                                        goto out_failure;
        !          2593:                                                                }
        !          2594: 
        !          2595:                                                                php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
        !          2596:                                                                return FAILURE;
        !          2597:                                                        }
        !          2598:                                                        pd = new_out_buf + (pd - out_buf);
        !          2599:                                                        ocnt += (new_out_buf_size - out_buf_size);
        !          2600:                                                        out_buf = new_out_buf;
        !          2601:                                                        out_buf_size = new_out_buf_size;
        !          2602:                                                }
        !          2603:                                        } break;
        !          2604: 
        !          2605:                                        default:
        !          2606:                                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unknown error", self->from_charset, self->to_charset);
        !          2607:                                                goto out_failure;
        !          2608:                                }
        !          2609: #else
        !          2610:                                if (ocnt == prev_ocnt) {
        !          2611:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unknown error", self->from_charset, self->to_charset);
        !          2612:                                        goto out_failure;
        !          2613:                                }
        !          2614: #endif
        !          2615:                        }
        !          2616:                        prev_ocnt = ocnt;
        !          2617:                }
        !          2618:                memmove(self->stub, pt, tcnt);
        !          2619:                self->stub_len = tcnt;
        !          2620:        }
        !          2621: 
        !          2622:        while (icnt > 0) {
        !          2623:                if ((ps == NULL ? iconv(self->cd, NULL, NULL, &pd, &ocnt):
        !          2624:                                        iconv(self->cd, (char **)&ps, &icnt, &pd, &ocnt)) == (size_t)-1) {
        !          2625: #if ICONV_SUPPORTS_ERRNO
        !          2626:                        switch (errno) {
        !          2627:                                case EILSEQ:
        !          2628:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): invalid multibyte sequence", self->from_charset, self->to_charset);
        !          2629:                                        goto out_failure;
        !          2630: 
        !          2631:                                case EINVAL:
        !          2632:                                        if (ps != NULL) {
        !          2633:                                                if (icnt > sizeof(self->stub)) {
        !          2634:                                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): insufficient buffer", self->from_charset, self->to_charset);
        !          2635:                                                        goto out_failure;
        !          2636:                                                }
        !          2637:                                                memcpy(self->stub, ps, icnt);
        !          2638:                                                self->stub_len = icnt;
        !          2639:                                                ps += icnt;
        !          2640:                                                icnt = 0;
        !          2641:                                        } else {
        !          2642:                                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unexpected octet values", self->from_charset, self->to_charset);
        !          2643:                                                goto out_failure;
        !          2644:                                        }
        !          2645:                                        break;
        !          2646: 
        !          2647:                                case E2BIG: {
        !          2648:                                        char *new_out_buf;
        !          2649:                                        size_t new_out_buf_size;
        !          2650: 
        !          2651:                                        new_out_buf_size = out_buf_size << 1;
        !          2652: 
        !          2653:                                        if (new_out_buf_size < out_buf_size) {
        !          2654:                                                /* whoa! no bigger buckets are sold anywhere... */
        !          2655:                                                if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
        !          2656:                                                        goto out_failure;
        !          2657:                                                }
        !          2658: 
        !          2659:                                                php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
        !          2660: 
        !          2661:                                                out_buf_size = ocnt = initial_out_buf_size;
        !          2662:                                                if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) {
        !          2663:                                                        return FAILURE;
        !          2664:                                                }
        !          2665:                                                pd = out_buf;
        !          2666:                                        } else {
        !          2667:                                                if (NULL == (new_out_buf = perealloc(out_buf, new_out_buf_size, persistent))) {
        !          2668:                                                        if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
        !          2669:                                                                goto out_failure;
        !          2670:                                                        }
        !          2671: 
        !          2672:                                                        php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
        !          2673:                                                        return FAILURE;
        !          2674:                                                }
        !          2675:                                                pd = new_out_buf + (pd - out_buf);
        !          2676:                                                ocnt += (new_out_buf_size - out_buf_size);
        !          2677:                                                out_buf = new_out_buf;
        !          2678:                                                out_buf_size = new_out_buf_size;
        !          2679:                                        }
        !          2680:                                } break;
        !          2681: 
        !          2682:                                default:
        !          2683:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unknown error", self->from_charset, self->to_charset);
        !          2684:                                        goto out_failure;
        !          2685:                        }
        !          2686: #else
        !          2687:                        if (ocnt == prev_ocnt) {
        !          2688:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unknown error", self->from_charset, self->to_charset);
        !          2689:                                goto out_failure;
        !          2690:                        }
        !          2691: #endif
        !          2692:                } else {
        !          2693:                        if (ps == NULL) {
        !          2694:                                break;
        !          2695:                        }
        !          2696:                }
        !          2697:                prev_ocnt = ocnt;
        !          2698:        }
        !          2699: 
        !          2700:        if (out_buf_size - ocnt > 0) {
        !          2701:                if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
        !          2702:                        goto out_failure;
        !          2703:                }
        !          2704:                php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
        !          2705:        } else {
        !          2706:                pefree(out_buf, persistent);
        !          2707:        }
        !          2708:        *consumed += buf_len - icnt;
        !          2709: 
        !          2710:        return SUCCESS;
        !          2711: 
        !          2712: out_failure:
        !          2713:        pefree(out_buf, persistent);
        !          2714:        return FAILURE;
        !          2715: }
        !          2716: /* }}} php_iconv_stream_filter_append_bucket */
        !          2717: 
        !          2718: /* {{{ php_iconv_stream_filter_do_filter */
        !          2719: static php_stream_filter_status_t php_iconv_stream_filter_do_filter(
        !          2720:                php_stream *stream, php_stream_filter *filter,
        !          2721:                php_stream_bucket_brigade *buckets_in,
        !          2722:                php_stream_bucket_brigade *buckets_out,
        !          2723:                size_t *bytes_consumed, int flags TSRMLS_DC)
        !          2724: {
        !          2725:        php_stream_bucket *bucket = NULL;
        !          2726:        size_t consumed = 0;
        !          2727:        php_iconv_stream_filter *self = (php_iconv_stream_filter *)filter->abstract;
        !          2728: 
        !          2729:        while (buckets_in->head != NULL) {
        !          2730:                bucket = buckets_in->head;
        !          2731: 
        !          2732:                php_stream_bucket_unlink(bucket TSRMLS_CC);
        !          2733: 
        !          2734:                if (php_iconv_stream_filter_append_bucket(self, stream, filter,
        !          2735:                                buckets_out, bucket->buf, bucket->buflen, &consumed,
        !          2736:                                php_stream_is_persistent(stream) TSRMLS_CC) != SUCCESS) {
        !          2737:                        goto out_failure;
        !          2738:                }
        !          2739: 
        !          2740:                php_stream_bucket_delref(bucket TSRMLS_CC);
        !          2741:        }
        !          2742: 
        !          2743:        if (flags != PSFS_FLAG_NORMAL) {
        !          2744:                if (php_iconv_stream_filter_append_bucket(self, stream, filter,
        !          2745:                                buckets_out, NULL, 0, &consumed,
        !          2746:                                php_stream_is_persistent(stream) TSRMLS_CC) != SUCCESS) {
        !          2747:                        goto out_failure;
        !          2748:                }
        !          2749:        }
        !          2750: 
        !          2751:        if (bytes_consumed != NULL) {
        !          2752:                *bytes_consumed = consumed;
        !          2753:        }
        !          2754: 
        !          2755:        return PSFS_PASS_ON;
        !          2756: 
        !          2757: out_failure:
        !          2758:        if (bucket != NULL) {
        !          2759:                php_stream_bucket_delref(bucket TSRMLS_CC);
        !          2760:        }
        !          2761:        return PSFS_ERR_FATAL;
        !          2762: }
        !          2763: /* }}} */
        !          2764: 
        !          2765: /* {{{ php_iconv_stream_filter_cleanup */
        !          2766: static void php_iconv_stream_filter_cleanup(php_stream_filter *filter TSRMLS_DC)
        !          2767: {
        !          2768:        php_iconv_stream_filter_dtor((php_iconv_stream_filter *)filter->abstract);
        !          2769:        pefree(filter->abstract, ((php_iconv_stream_filter *)filter->abstract)->persistent);
        !          2770: }
        !          2771: /* }}} */
        !          2772: 
        !          2773: static php_stream_filter_ops php_iconv_stream_filter_ops = {
        !          2774:        php_iconv_stream_filter_do_filter,
        !          2775:        php_iconv_stream_filter_cleanup,
        !          2776:        "convert.iconv.*"
        !          2777: };
        !          2778: 
        !          2779: /* {{{ php_iconv_stream_filter_create */
        !          2780: static php_stream_filter *php_iconv_stream_filter_factory_create(const char *name, zval *params, int persistent TSRMLS_DC)
        !          2781: {
        !          2782:        php_stream_filter *retval = NULL;
        !          2783:        php_iconv_stream_filter *inst;
        !          2784:        char *from_charset = NULL, *to_charset = NULL;
        !          2785:        size_t from_charset_len, to_charset_len;
        !          2786: 
        !          2787:        if ((from_charset = strchr(name, '.')) == NULL) {
        !          2788:                return NULL;
        !          2789:        }
        !          2790:        ++from_charset;
        !          2791:        if ((from_charset = strchr(from_charset, '.')) == NULL) {
        !          2792:                return NULL;
        !          2793:        }
        !          2794:        ++from_charset;
        !          2795:        if ((to_charset = strpbrk(from_charset, "/.")) == NULL) {
        !          2796:                return NULL;
        !          2797:        }
        !          2798:        from_charset_len = to_charset - from_charset;
        !          2799:        ++to_charset;
        !          2800:        to_charset_len = strlen(to_charset);
        !          2801: 
        !          2802:        if (from_charset_len >= ICONV_CSNMAXLEN || to_charset_len >= ICONV_CSNMAXLEN) {
        !          2803:                return NULL;
        !          2804:        }
        !          2805: 
        !          2806:        if (NULL == (inst = pemalloc(sizeof(php_iconv_stream_filter), persistent))) {
        !          2807:                return NULL;
        !          2808:        }
        !          2809: 
        !          2810:        if (php_iconv_stream_filter_ctor(inst, to_charset, to_charset_len, from_charset, from_charset_len, persistent) != PHP_ICONV_ERR_SUCCESS) {
        !          2811:                pefree(inst, persistent);
        !          2812:                return NULL;
        !          2813:        }
        !          2814: 
        !          2815:        if (NULL == (retval = php_stream_filter_alloc(&php_iconv_stream_filter_ops, inst, persistent))) {
        !          2816:                php_iconv_stream_filter_dtor(inst);
        !          2817:                pefree(inst, persistent);
        !          2818:        }
        !          2819: 
        !          2820:        return retval;  
        !          2821: }
        !          2822: /* }}} */
        !          2823: 
        !          2824: /* {{{ php_iconv_stream_register_factory */
        !          2825: static php_iconv_err_t php_iconv_stream_filter_register_factory(TSRMLS_D)
        !          2826: {
        !          2827:        static php_stream_filter_factory filter_factory = {
        !          2828:                php_iconv_stream_filter_factory_create
        !          2829:        };
        !          2830: 
        !          2831:        if (FAILURE == php_stream_filter_register_factory(
        !          2832:                                php_iconv_stream_filter_ops.label,
        !          2833:                                &filter_factory TSRMLS_CC)) {
        !          2834:                return PHP_ICONV_ERR_UNKNOWN;
        !          2835:        }
        !          2836:        return PHP_ICONV_ERR_SUCCESS;
        !          2837: }
        !          2838: /* }}} */
        !          2839: 
        !          2840: /* {{{ php_iconv_stream_unregister_factory */
        !          2841: static php_iconv_err_t php_iconv_stream_filter_unregister_factory(TSRMLS_D)
        !          2842: {
        !          2843:        if (FAILURE == php_stream_filter_unregister_factory(
        !          2844:                                php_iconv_stream_filter_ops.label TSRMLS_CC)) {
        !          2845:                return PHP_ICONV_ERR_UNKNOWN;
        !          2846:        }
        !          2847:        return PHP_ICONV_ERR_SUCCESS;
        !          2848: }
        !          2849: /* }}} */
        !          2850: /* }}} */
        !          2851: #endif
        !          2852: 
        !          2853: /*
        !          2854:  * Local variables:
        !          2855:  * tab-width: 4
        !          2856:  * c-basic-offset: 4
        !          2857:  * End:
        !          2858:  * vim600: sw=4 ts=4 fdm=marker
        !          2859:  * vim<600: sw=4 ts=4
        !          2860:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>