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

LCOV - code coverage report
Current view: top level - ext/iconv - iconv.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 900 1216 74.0 %
Date: 2014-10-14 Functions: 40 40 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Tue, 14 Oct 2014 07:25:40 +0000 (7 days ago)

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