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

Generated by: LTP GCOV extension version 1.5

Generated at Sat, 21 Nov 2009 12:27:01 +0000 (3 days ago)

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