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

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

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

Generated by: LTP GCOV extension version 1.5

Generated at Thu, 19 Nov 2009 08:20:09 +0000 (5 days ago)

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