LTP GCOV extension - code coverage report
Current view: directory - ext/iconv - iconv.c
Test: PHP Code Coverage
Date: 2007-04-10 Instrumented lines: 1144
Code covered: 4.7 % Executed lines: 54
Legend: not executed executed

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

Generated by: LTP GCOV extension version 1.5