PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LTP GCOV extension - code coverage report
Current view: directory - iconv - iconv.c
Test: PHP Code Coverage
Date: 2009-11-23 Instrumented lines: 1059
Code covered: 68.3 % Executed lines: 723
Legend: not executed executed

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

Generated by: LTP GCOV extension version 1.5

Generated at Mon, 23 Nov 2009 17:39:31 +0000 (33 hours ago)

Copyright © 2005-2009 The PHP Group
All rights reserved.