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/mbstring - mbstring.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 2052 2563 80.1 %
Date: 2016-09-27 Functions: 103 109 94.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 7                                                        |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1997-2016 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             :    | Author: Tsukada Takuya <tsukada@fminn.nagano.nagano.jp>              |
      16             :    |         Rui Hirokawa <hirokawa@php.net>                              |
      17             :    +----------------------------------------------------------------------+
      18             :  */
      19             : 
      20             : /* $Id$ */
      21             : 
      22             : /*
      23             :  * PHP 4 Multibyte String module "mbstring"
      24             :  *
      25             :  * History:
      26             :  *   2000.5.19  Release php-4.0RC2_jstring-1.0
      27             :  *   2001.4.1   Release php4_jstring-1.0.91
      28             :  *   2001.4.30  Release php4_jstring-1.1 (contribute to The PHP Group)
      29             :  *   2001.5.1   Renamed from jstring to mbstring (hirokawa@php.net)
      30             :  */
      31             : 
      32             : /*
      33             :  * PHP3 Internationalization support program.
      34             :  *
      35             :  * Copyright (c) 1999,2000 by the PHP3 internationalization team.
      36             :  * All rights reserved.
      37             :  *
      38             :  * See README_PHP3-i18n-ja for more detail.
      39             :  *
      40             :  * Authors:
      41             :  *    Hironori Sato <satoh@jpnnet.com>
      42             :  *    Shigeru Kanemoto <sgk@happysize.co.jp>
      43             :  *    Tsukada Takuya <tsukada@fminn.nagano.nagano.jp>
      44             :  *    Rui Hirokawa <rui_hirokawa@ybb.ne.jp>
      45             :  */
      46             : 
      47             : /* {{{ includes */
      48             : #ifdef HAVE_CONFIG_H
      49             : #include "config.h"
      50             : #endif
      51             : 
      52             : #include "php.h"
      53             : #include "php_ini.h"
      54             : #include "php_variables.h"
      55             : #include "mbstring.h"
      56             : #include "ext/standard/php_string.h"
      57             : #include "ext/standard/php_mail.h"
      58             : #include "ext/standard/exec.h"
      59             : #include "ext/standard/url.h"
      60             : #include "main/php_output.h"
      61             : #include "ext/standard/info.h"
      62             : 
      63             : #include "libmbfl/mbfl/mbfl_allocators.h"
      64             : #include "libmbfl/mbfl/mbfilter_pass.h"
      65             : 
      66             : #include "php_variables.h"
      67             : #include "php_globals.h"
      68             : #include "rfc1867.h"
      69             : #include "php_content_types.h"
      70             : #include "SAPI.h"
      71             : #include "php_unicode.h"
      72             : #include "TSRM.h"
      73             : 
      74             : #include "mb_gpc.h"
      75             : 
      76             : #if HAVE_MBREGEX
      77             : #include "php_mbregex.h"
      78             : #endif
      79             : 
      80             : #include "zend_multibyte.h"
      81             : 
      82             : #if HAVE_ONIG
      83             : #include "php_onig_compat.h"
      84             : #include <oniguruma.h>
      85             : #undef UChar
      86             : #elif HAVE_PCRE || HAVE_BUNDLED_PCRE
      87             : #include "ext/pcre/php_pcre.h"
      88             : #endif
      89             : /* }}} */
      90             : 
      91             : #if HAVE_MBSTRING
      92             : 
      93             : /* {{{ prototypes */
      94             : ZEND_DECLARE_MODULE_GLOBALS(mbstring)
      95             : 
      96             : static PHP_GINIT_FUNCTION(mbstring);
      97             : static PHP_GSHUTDOWN_FUNCTION(mbstring);
      98             : 
      99             : static void php_mb_populate_current_detect_order_list(void);
     100             : 
     101             : static int php_mb_encoding_translation(void);
     102             : 
     103             : static void php_mb_gpc_get_detect_order(const zend_encoding ***list, size_t *list_size);
     104             : 
     105             : static void php_mb_gpc_set_input_encoding(const zend_encoding *encoding);
     106             : 
     107             : /* }}} */
     108             : 
     109             : /* {{{ php_mb_default_identify_list */
     110             : typedef struct _php_mb_nls_ident_list {
     111             :         enum mbfl_no_language lang;
     112             :         const enum mbfl_no_encoding *list;
     113             :         size_t list_size;
     114             : } php_mb_nls_ident_list;
     115             : 
     116             : static const enum mbfl_no_encoding php_mb_default_identify_list_ja[] = {
     117             :         mbfl_no_encoding_ascii,
     118             :         mbfl_no_encoding_jis,
     119             :         mbfl_no_encoding_utf8,
     120             :         mbfl_no_encoding_euc_jp,
     121             :         mbfl_no_encoding_sjis
     122             : };
     123             : 
     124             : static const enum mbfl_no_encoding php_mb_default_identify_list_cn[] = {
     125             :         mbfl_no_encoding_ascii,
     126             :         mbfl_no_encoding_utf8,
     127             :         mbfl_no_encoding_euc_cn,
     128             :         mbfl_no_encoding_cp936
     129             : };
     130             : 
     131             : static const enum mbfl_no_encoding php_mb_default_identify_list_tw_hk[] = {
     132             :         mbfl_no_encoding_ascii,
     133             :         mbfl_no_encoding_utf8,
     134             :         mbfl_no_encoding_euc_tw,
     135             :         mbfl_no_encoding_big5
     136             : };
     137             : 
     138             : static const enum mbfl_no_encoding php_mb_default_identify_list_kr[] = {
     139             :         mbfl_no_encoding_ascii,
     140             :         mbfl_no_encoding_utf8,
     141             :         mbfl_no_encoding_euc_kr,
     142             :         mbfl_no_encoding_uhc
     143             : };
     144             : 
     145             : static const enum mbfl_no_encoding php_mb_default_identify_list_ru[] = {
     146             :         mbfl_no_encoding_ascii,
     147             :         mbfl_no_encoding_utf8,
     148             :         mbfl_no_encoding_koi8r,
     149             :         mbfl_no_encoding_cp1251,
     150             :         mbfl_no_encoding_cp866
     151             : };
     152             : 
     153             : static const enum mbfl_no_encoding php_mb_default_identify_list_hy[] = {
     154             :         mbfl_no_encoding_ascii,
     155             :         mbfl_no_encoding_utf8,
     156             :         mbfl_no_encoding_armscii8
     157             : };
     158             : 
     159             : static const enum mbfl_no_encoding php_mb_default_identify_list_tr[] = {
     160             :         mbfl_no_encoding_ascii,
     161             :         mbfl_no_encoding_utf8,
     162             :         mbfl_no_encoding_cp1254,
     163             :         mbfl_no_encoding_8859_9
     164             : };
     165             : 
     166             : static const enum mbfl_no_encoding php_mb_default_identify_list_ua[] = {
     167             :         mbfl_no_encoding_ascii,
     168             :         mbfl_no_encoding_utf8,
     169             :         mbfl_no_encoding_koi8u
     170             : };
     171             : 
     172             : static const enum mbfl_no_encoding php_mb_default_identify_list_neut[] = {
     173             :         mbfl_no_encoding_ascii,
     174             :         mbfl_no_encoding_utf8
     175             : };
     176             : 
     177             : 
     178             : static const php_mb_nls_ident_list php_mb_default_identify_list[] = {
     179             :         { mbfl_no_language_japanese, php_mb_default_identify_list_ja, sizeof(php_mb_default_identify_list_ja) / sizeof(php_mb_default_identify_list_ja[0]) },
     180             :         { mbfl_no_language_korean, php_mb_default_identify_list_kr, sizeof(php_mb_default_identify_list_kr) / sizeof(php_mb_default_identify_list_kr[0]) },
     181             :         { mbfl_no_language_traditional_chinese, php_mb_default_identify_list_tw_hk, sizeof(php_mb_default_identify_list_tw_hk) / sizeof(php_mb_default_identify_list_tw_hk[0]) },
     182             :         { mbfl_no_language_simplified_chinese, php_mb_default_identify_list_cn, sizeof(php_mb_default_identify_list_cn) / sizeof(php_mb_default_identify_list_cn[0]) },
     183             :         { mbfl_no_language_russian, php_mb_default_identify_list_ru, sizeof(php_mb_default_identify_list_ru) / sizeof(php_mb_default_identify_list_ru[0]) },
     184             :         { mbfl_no_language_armenian, php_mb_default_identify_list_hy, sizeof(php_mb_default_identify_list_hy) / sizeof(php_mb_default_identify_list_hy[0]) },
     185             :         { mbfl_no_language_turkish, php_mb_default_identify_list_tr, sizeof(php_mb_default_identify_list_tr) / sizeof(php_mb_default_identify_list_tr[0]) },
     186             :         { mbfl_no_language_ukrainian, php_mb_default_identify_list_ua, sizeof(php_mb_default_identify_list_ua) / sizeof(php_mb_default_identify_list_ua[0]) },
     187             :         { mbfl_no_language_neutral, php_mb_default_identify_list_neut, sizeof(php_mb_default_identify_list_neut) / sizeof(php_mb_default_identify_list_neut[0]) }
     188             : };
     189             : 
     190             : /* }}} */
     191             : 
     192             : /* {{{ mb_overload_def mb_ovld[] */
     193             : static const struct mb_overload_def mb_ovld[] = {
     194             :         {MB_OVERLOAD_MAIL, "mail", "mb_send_mail", "mb_orig_mail"},
     195             :         {MB_OVERLOAD_STRING, "strlen", "mb_strlen", "mb_orig_strlen"},
     196             :         {MB_OVERLOAD_STRING, "strpos", "mb_strpos", "mb_orig_strpos"},
     197             :         {MB_OVERLOAD_STRING, "strrpos", "mb_strrpos", "mb_orig_strrpos"},
     198             :         {MB_OVERLOAD_STRING, "stripos", "mb_stripos", "mb_orig_stripos"},
     199             :         {MB_OVERLOAD_STRING, "strripos", "mb_strripos", "mb_orig_strripos"},
     200             :         {MB_OVERLOAD_STRING, "strstr", "mb_strstr", "mb_orig_strstr"},
     201             :         {MB_OVERLOAD_STRING, "strrchr", "mb_strrchr", "mb_orig_strrchr"},
     202             :         {MB_OVERLOAD_STRING, "stristr", "mb_stristr", "mb_orig_stristr"},
     203             :         {MB_OVERLOAD_STRING, "substr", "mb_substr", "mb_orig_substr"},
     204             :         {MB_OVERLOAD_STRING, "strtolower", "mb_strtolower", "mb_orig_strtolower"},
     205             :         {MB_OVERLOAD_STRING, "strtoupper", "mb_strtoupper", "mb_orig_strtoupper"},
     206             :         {MB_OVERLOAD_STRING, "substr_count", "mb_substr_count", "mb_orig_substr_count"},
     207             :         {0, NULL, NULL, NULL}
     208             : };
     209             : /* }}} */
     210             : 
     211             : /* {{{ arginfo */
     212             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_language, 0, 0, 0)
     213             :         ZEND_ARG_INFO(0, language)
     214             : ZEND_END_ARG_INFO()
     215             : 
     216             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_internal_encoding, 0, 0, 0)
     217             :         ZEND_ARG_INFO(0, encoding)
     218             : ZEND_END_ARG_INFO()
     219             : 
     220             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_http_input, 0, 0, 0)
     221             :         ZEND_ARG_INFO(0, type)
     222             : ZEND_END_ARG_INFO()
     223             : 
     224             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_http_output, 0, 0, 0)
     225             :         ZEND_ARG_INFO(0, encoding)
     226             : ZEND_END_ARG_INFO()
     227             : 
     228             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_detect_order, 0, 0, 0)
     229             :         ZEND_ARG_INFO(0, encoding)
     230             : ZEND_END_ARG_INFO()
     231             : 
     232             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_substitute_character, 0, 0, 0)
     233             :         ZEND_ARG_INFO(0, substchar)
     234             : ZEND_END_ARG_INFO()
     235             : 
     236             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_preferred_mime_name, 0, 0, 1)
     237             :         ZEND_ARG_INFO(0, encoding)
     238             : ZEND_END_ARG_INFO()
     239             : 
     240             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_parse_str, 0, 0, 1)
     241             :         ZEND_ARG_INFO(0, encoded_string)
     242             :         ZEND_ARG_INFO(1, result)
     243             : ZEND_END_ARG_INFO()
     244             : 
     245             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_output_handler, 0, 0, 2)
     246             :         ZEND_ARG_INFO(0, contents)
     247             :         ZEND_ARG_INFO(0, status)
     248             : ZEND_END_ARG_INFO()
     249             : 
     250             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strlen, 0, 0, 1)
     251             :         ZEND_ARG_INFO(0, str)
     252             :         ZEND_ARG_INFO(0, encoding)
     253             : ZEND_END_ARG_INFO()
     254             : 
     255             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strpos, 0, 0, 2)
     256             :         ZEND_ARG_INFO(0, haystack)
     257             :         ZEND_ARG_INFO(0, needle)
     258             :         ZEND_ARG_INFO(0, offset)
     259             :         ZEND_ARG_INFO(0, encoding)
     260             : ZEND_END_ARG_INFO()
     261             : 
     262             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strrpos, 0, 0, 2)
     263             :         ZEND_ARG_INFO(0, haystack)
     264             :         ZEND_ARG_INFO(0, needle)
     265             :         ZEND_ARG_INFO(0, offset)
     266             :         ZEND_ARG_INFO(0, encoding)
     267             : ZEND_END_ARG_INFO()
     268             : 
     269             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_stripos, 0, 0, 2)
     270             :         ZEND_ARG_INFO(0, haystack)
     271             :         ZEND_ARG_INFO(0, needle)
     272             :         ZEND_ARG_INFO(0, offset)
     273             :         ZEND_ARG_INFO(0, encoding)
     274             : ZEND_END_ARG_INFO()
     275             : 
     276             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strripos, 0, 0, 2)
     277             :         ZEND_ARG_INFO(0, haystack)
     278             :         ZEND_ARG_INFO(0, needle)
     279             :         ZEND_ARG_INFO(0, offset)
     280             :         ZEND_ARG_INFO(0, encoding)
     281             : ZEND_END_ARG_INFO()
     282             : 
     283             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strstr, 0, 0, 2)
     284             :         ZEND_ARG_INFO(0, haystack)
     285             :         ZEND_ARG_INFO(0, needle)
     286             :         ZEND_ARG_INFO(0, part)
     287             :         ZEND_ARG_INFO(0, encoding)
     288             : ZEND_END_ARG_INFO()
     289             : 
     290             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strrchr, 0, 0, 2)
     291             :         ZEND_ARG_INFO(0, haystack)
     292             :         ZEND_ARG_INFO(0, needle)
     293             :         ZEND_ARG_INFO(0, part)
     294             :         ZEND_ARG_INFO(0, encoding)
     295             : ZEND_END_ARG_INFO()
     296             : 
     297             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_stristr, 0, 0, 2)
     298             :         ZEND_ARG_INFO(0, haystack)
     299             :         ZEND_ARG_INFO(0, needle)
     300             :         ZEND_ARG_INFO(0, part)
     301             :         ZEND_ARG_INFO(0, encoding)
     302             : ZEND_END_ARG_INFO()
     303             : 
     304             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strrichr, 0, 0, 2)
     305             :         ZEND_ARG_INFO(0, haystack)
     306             :         ZEND_ARG_INFO(0, needle)
     307             :         ZEND_ARG_INFO(0, part)
     308             :         ZEND_ARG_INFO(0, encoding)
     309             : ZEND_END_ARG_INFO()
     310             : 
     311             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_substr_count, 0, 0, 2)
     312             :         ZEND_ARG_INFO(0, haystack)
     313             :         ZEND_ARG_INFO(0, needle)
     314             :         ZEND_ARG_INFO(0, encoding)
     315             : ZEND_END_ARG_INFO()
     316             : 
     317             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_substr, 0, 0, 2)
     318             :         ZEND_ARG_INFO(0, str)
     319             :         ZEND_ARG_INFO(0, start)
     320             :         ZEND_ARG_INFO(0, length)
     321             :         ZEND_ARG_INFO(0, encoding)
     322             : ZEND_END_ARG_INFO()
     323             : 
     324             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strcut, 0, 0, 2)
     325             :         ZEND_ARG_INFO(0, str)
     326             :         ZEND_ARG_INFO(0, start)
     327             :         ZEND_ARG_INFO(0, length)
     328             :         ZEND_ARG_INFO(0, encoding)
     329             : ZEND_END_ARG_INFO()
     330             : 
     331             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strwidth, 0, 0, 1)
     332             :         ZEND_ARG_INFO(0, str)
     333             :         ZEND_ARG_INFO(0, encoding)
     334             : ZEND_END_ARG_INFO()
     335             : 
     336             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strimwidth, 0, 0, 3)
     337             :         ZEND_ARG_INFO(0, str)
     338             :         ZEND_ARG_INFO(0, start)
     339             :         ZEND_ARG_INFO(0, width)
     340             :         ZEND_ARG_INFO(0, trimmarker)
     341             :         ZEND_ARG_INFO(0, encoding)
     342             : ZEND_END_ARG_INFO()
     343             : 
     344             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_convert_encoding, 0, 0, 2)
     345             :         ZEND_ARG_INFO(0, str)
     346             :         ZEND_ARG_INFO(0, to)
     347             :         ZEND_ARG_INFO(0, from)
     348             : ZEND_END_ARG_INFO()
     349             : 
     350             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_convert_case, 0, 0, 2)
     351             :         ZEND_ARG_INFO(0, sourcestring)
     352             :         ZEND_ARG_INFO(0, mode)
     353             :         ZEND_ARG_INFO(0, encoding)
     354             : ZEND_END_ARG_INFO()
     355             : 
     356             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strtoupper, 0, 0, 1)
     357             :         ZEND_ARG_INFO(0, sourcestring)
     358             :         ZEND_ARG_INFO(0, encoding)
     359             : ZEND_END_ARG_INFO()
     360             : 
     361             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strtolower, 0, 0, 1)
     362             :         ZEND_ARG_INFO(0, sourcestring)
     363             :         ZEND_ARG_INFO(0, encoding)
     364             : ZEND_END_ARG_INFO()
     365             : 
     366             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_detect_encoding, 0, 0, 1)
     367             :         ZEND_ARG_INFO(0, str)
     368             :         ZEND_ARG_INFO(0, encoding_list)
     369             :         ZEND_ARG_INFO(0, strict)
     370             : ZEND_END_ARG_INFO()
     371             : 
     372             : ZEND_BEGIN_ARG_INFO(arginfo_mb_list_encodings, 0)
     373             : ZEND_END_ARG_INFO()
     374             : 
     375             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_encoding_aliases, 0, 0, 1)
     376             :         ZEND_ARG_INFO(0, encoding)
     377             : ZEND_END_ARG_INFO()
     378             : 
     379             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_encode_mimeheader, 0, 0, 1)
     380             :         ZEND_ARG_INFO(0, str)
     381             :         ZEND_ARG_INFO(0, charset)
     382             :         ZEND_ARG_INFO(0, transfer)
     383             :         ZEND_ARG_INFO(0, linefeed)
     384             :         ZEND_ARG_INFO(0, indent)
     385             : ZEND_END_ARG_INFO()
     386             : 
     387             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_decode_mimeheader, 0, 0, 1)
     388             :         ZEND_ARG_INFO(0, string)
     389             : ZEND_END_ARG_INFO()
     390             : 
     391             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_convert_kana, 0, 0, 1)
     392             :         ZEND_ARG_INFO(0, str)
     393             :         ZEND_ARG_INFO(0, option)
     394             :         ZEND_ARG_INFO(0, encoding)
     395             : ZEND_END_ARG_INFO()
     396             : 
     397             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_convert_variables, 0, 0, 3)
     398             :         ZEND_ARG_INFO(0, to)
     399             :         ZEND_ARG_INFO(0, from)
     400             :         ZEND_ARG_VARIADIC_INFO(1, vars)
     401             : ZEND_END_ARG_INFO()
     402             : 
     403             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_encode_numericentity, 0, 0, 2)
     404             :         ZEND_ARG_INFO(0, string)
     405             :         ZEND_ARG_INFO(0, convmap)
     406             :         ZEND_ARG_INFO(0, encoding)
     407             :         ZEND_ARG_INFO(0, is_hex)
     408             : ZEND_END_ARG_INFO()
     409             : 
     410             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_decode_numericentity, 0, 0, 2)
     411             :         ZEND_ARG_INFO(0, string)
     412             :         ZEND_ARG_INFO(0, convmap)
     413             :         ZEND_ARG_INFO(0, encoding)
     414             : ZEND_END_ARG_INFO()
     415             : 
     416             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_send_mail, 0, 0, 3)
     417             :         ZEND_ARG_INFO(0, to)
     418             :         ZEND_ARG_INFO(0, subject)
     419             :         ZEND_ARG_INFO(0, message)
     420             :         ZEND_ARG_INFO(0, additional_headers)
     421             :         ZEND_ARG_INFO(0, additional_parameters)
     422             : ZEND_END_ARG_INFO()
     423             : 
     424             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_get_info, 0, 0, 0)
     425             :         ZEND_ARG_INFO(0, type)
     426             : ZEND_END_ARG_INFO()
     427             : 
     428             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_check_encoding, 0, 0, 0)
     429             :         ZEND_ARG_INFO(0, var)
     430             :         ZEND_ARG_INFO(0, encoding)
     431             : ZEND_END_ARG_INFO()
     432             : 
     433             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_scrub, 0, 0, 1)
     434             :         ZEND_ARG_INFO(0, str)
     435             :         ZEND_ARG_INFO(0, encoding)
     436             : ZEND_END_ARG_INFO()
     437             : 
     438             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ord, 0, 0, 1)
     439             :         ZEND_ARG_INFO(0, str)
     440             :         ZEND_ARG_INFO(0, encoding)
     441             : ZEND_END_ARG_INFO()
     442             : 
     443             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_chr, 0, 0, 1)
     444             :         ZEND_ARG_INFO(0, cp)
     445             :         ZEND_ARG_INFO(0, encoding)
     446             : ZEND_END_ARG_INFO()
     447             : 
     448             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_regex_encoding, 0, 0, 0)
     449             :         ZEND_ARG_INFO(0, encoding)
     450             : ZEND_END_ARG_INFO()
     451             : 
     452             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg, 0, 0, 2)
     453             :         ZEND_ARG_INFO(0, pattern)
     454             :         ZEND_ARG_INFO(0, string)
     455             :         ZEND_ARG_INFO(1, registers)
     456             : ZEND_END_ARG_INFO()
     457             : 
     458             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_eregi, 0, 0, 2)
     459             :         ZEND_ARG_INFO(0, pattern)
     460             :         ZEND_ARG_INFO(0, string)
     461             :         ZEND_ARG_INFO(1, registers)
     462             : ZEND_END_ARG_INFO()
     463             : 
     464             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_replace, 0, 0, 3)
     465             :         ZEND_ARG_INFO(0, pattern)
     466             :         ZEND_ARG_INFO(0, replacement)
     467             :         ZEND_ARG_INFO(0, string)
     468             :         ZEND_ARG_INFO(0, option)
     469             : ZEND_END_ARG_INFO()
     470             : 
     471             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_eregi_replace, 0, 0, 3)
     472             :         ZEND_ARG_INFO(0, pattern)
     473             :         ZEND_ARG_INFO(0, replacement)
     474             :         ZEND_ARG_INFO(0, string)
     475             : ZEND_END_ARG_INFO()
     476             : 
     477             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_replace_callback, 0, 0, 3)
     478             :         ZEND_ARG_INFO(0, pattern)
     479             :         ZEND_ARG_INFO(0, callback)
     480             :         ZEND_ARG_INFO(0, string)
     481             :         ZEND_ARG_INFO(0, option)
     482             : ZEND_END_ARG_INFO()
     483             : 
     484             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_split, 0, 0, 2)
     485             :         ZEND_ARG_INFO(0, pattern)
     486             :         ZEND_ARG_INFO(0, string)
     487             :         ZEND_ARG_INFO(0, limit)
     488             : ZEND_END_ARG_INFO()
     489             : 
     490             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_match, 0, 0, 2)
     491             :         ZEND_ARG_INFO(0, pattern)
     492             :         ZEND_ARG_INFO(0, string)
     493             :         ZEND_ARG_INFO(0, option)
     494             : ZEND_END_ARG_INFO()
     495             : 
     496             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_search, 0, 0, 0)
     497             :         ZEND_ARG_INFO(0, pattern)
     498             :         ZEND_ARG_INFO(0, option)
     499             : ZEND_END_ARG_INFO()
     500             : 
     501             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_search_pos, 0, 0, 0)
     502             :         ZEND_ARG_INFO(0, pattern)
     503             :         ZEND_ARG_INFO(0, option)
     504             : ZEND_END_ARG_INFO()
     505             : 
     506             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_search_regs, 0, 0, 0)
     507             :         ZEND_ARG_INFO(0, pattern)
     508             :         ZEND_ARG_INFO(0, option)
     509             : ZEND_END_ARG_INFO()
     510             : 
     511             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_search_init, 0, 0, 1)
     512             :         ZEND_ARG_INFO(0, string)
     513             :         ZEND_ARG_INFO(0, pattern)
     514             :         ZEND_ARG_INFO(0, option)
     515             : ZEND_END_ARG_INFO()
     516             : 
     517             : ZEND_BEGIN_ARG_INFO(arginfo_mb_ereg_search_getregs, 0)
     518             : ZEND_END_ARG_INFO()
     519             : 
     520             : ZEND_BEGIN_ARG_INFO(arginfo_mb_ereg_search_getpos, 0)
     521             : ZEND_END_ARG_INFO()
     522             : 
     523             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_search_setpos, 0, 0, 1)
     524             :         ZEND_ARG_INFO(0, position)
     525             : ZEND_END_ARG_INFO()
     526             : 
     527             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_regex_set_options, 0, 0, 0)
     528             :         ZEND_ARG_INFO(0, options)
     529             : ZEND_END_ARG_INFO()
     530             : /* }}} */
     531             : 
     532             : /* {{{ zend_function_entry mbstring_functions[] */
     533             : const zend_function_entry mbstring_functions[] = {
     534             :         PHP_FE(mb_convert_case,                 arginfo_mb_convert_case)
     535             :         PHP_FE(mb_strtoupper,                   arginfo_mb_strtoupper)
     536             :         PHP_FE(mb_strtolower,                   arginfo_mb_strtolower)
     537             :         PHP_FE(mb_language,                             arginfo_mb_language)
     538             :         PHP_FE(mb_internal_encoding,    arginfo_mb_internal_encoding)
     539             :         PHP_FE(mb_http_input,                   arginfo_mb_http_input)
     540             :         PHP_FE(mb_http_output,                  arginfo_mb_http_output)
     541             :         PHP_FE(mb_detect_order,                 arginfo_mb_detect_order)
     542             :         PHP_FE(mb_substitute_character, arginfo_mb_substitute_character)
     543             :         PHP_FE(mb_parse_str,                    arginfo_mb_parse_str)
     544             :         PHP_FE(mb_output_handler,               arginfo_mb_output_handler)
     545             :         PHP_FE(mb_preferred_mime_name,  arginfo_mb_preferred_mime_name)
     546             :         PHP_FE(mb_strlen,                               arginfo_mb_strlen)
     547             :         PHP_FE(mb_strpos,                               arginfo_mb_strpos)
     548             :         PHP_FE(mb_strrpos,                              arginfo_mb_strrpos)
     549             :         PHP_FE(mb_stripos,                              arginfo_mb_stripos)
     550             :         PHP_FE(mb_strripos,                             arginfo_mb_strripos)
     551             :         PHP_FE(mb_strstr,                               arginfo_mb_strstr)
     552             :         PHP_FE(mb_strrchr,                              arginfo_mb_strrchr)
     553             :         PHP_FE(mb_stristr,                              arginfo_mb_stristr)
     554             :         PHP_FE(mb_strrichr,                             arginfo_mb_strrichr)
     555             :         PHP_FE(mb_substr_count,                 arginfo_mb_substr_count)
     556             :         PHP_FE(mb_substr,                               arginfo_mb_substr)
     557             :         PHP_FE(mb_strcut,                               arginfo_mb_strcut)
     558             :         PHP_FE(mb_strwidth,                             arginfo_mb_strwidth)
     559             :         PHP_FE(mb_strimwidth,                   arginfo_mb_strimwidth)
     560             :         PHP_FE(mb_convert_encoding,             arginfo_mb_convert_encoding)
     561             :         PHP_FE(mb_detect_encoding,              arginfo_mb_detect_encoding)
     562             :         PHP_FE(mb_list_encodings,               arginfo_mb_list_encodings)
     563             :         PHP_FE(mb_encoding_aliases,             arginfo_mb_encoding_aliases)
     564             :         PHP_FE(mb_convert_kana,                 arginfo_mb_convert_kana)
     565             :         PHP_FE(mb_encode_mimeheader,    arginfo_mb_encode_mimeheader)
     566             :         PHP_FE(mb_decode_mimeheader,    arginfo_mb_decode_mimeheader)
     567             :         PHP_FE(mb_convert_variables,    arginfo_mb_convert_variables)
     568             :         PHP_FE(mb_encode_numericentity, arginfo_mb_encode_numericentity)
     569             :         PHP_FE(mb_decode_numericentity, arginfo_mb_decode_numericentity)
     570             :         PHP_FE(mb_send_mail,                    arginfo_mb_send_mail)
     571             :         PHP_FE(mb_get_info,                             arginfo_mb_get_info)
     572             :         PHP_FE(mb_check_encoding,               arginfo_mb_check_encoding)
     573             :         PHP_FE(mb_ord,                                  arginfo_mb_ord)
     574             :         PHP_FE(mb_chr,                                  arginfo_mb_chr)
     575             :         PHP_FE(mb_scrub,                                arginfo_mb_scrub)
     576             : #if HAVE_MBREGEX
     577             :         PHP_MBREGEX_FUNCTION_ENTRIES
     578             : #endif
     579             :         PHP_FE_END
     580             : };
     581             : /* }}} */
     582             : 
     583             : /* {{{ zend_module_entry mbstring_module_entry */
     584             : zend_module_entry mbstring_module_entry = {
     585             :         STANDARD_MODULE_HEADER,
     586             :         "mbstring",
     587             :         mbstring_functions,
     588             :         PHP_MINIT(mbstring),
     589             :         PHP_MSHUTDOWN(mbstring),
     590             :         PHP_RINIT(mbstring),
     591             :         PHP_RSHUTDOWN(mbstring),
     592             :         PHP_MINFO(mbstring),
     593             :         PHP_MBSTRING_VERSION,
     594             :         PHP_MODULE_GLOBALS(mbstring),
     595             :         PHP_GINIT(mbstring),
     596             :         PHP_GSHUTDOWN(mbstring),
     597             :         NULL,
     598             :         STANDARD_MODULE_PROPERTIES_EX
     599             : };
     600             : /* }}} */
     601             : 
     602             : /* {{{ static sapi_post_entry php_post_entries[] */
     603             : static sapi_post_entry php_post_entries[] = {
     604             :         { DEFAULT_POST_CONTENT_TYPE, sizeof(DEFAULT_POST_CONTENT_TYPE)-1, sapi_read_standard_form_data, php_std_post_handler },
     605             :         { MULTIPART_CONTENT_TYPE,    sizeof(MULTIPART_CONTENT_TYPE)-1,    NULL,                         rfc1867_post_handler },
     606             :         { NULL, 0, NULL, NULL }
     607             : };
     608             : /* }}} */
     609             : 
     610             : #ifdef COMPILE_DL_MBSTRING
     611             : #ifdef ZTS
     612             : ZEND_TSRMLS_CACHE_DEFINE()
     613             : #endif
     614             : ZEND_GET_MODULE(mbstring)
     615             : #endif
     616             : 
     617       47682 : static char *get_internal_encoding(void) {
     618       47682 :         if (PG(internal_encoding) && PG(internal_encoding)[0]) {
     619          32 :                 return PG(internal_encoding);
     620       47650 :         } else if (SG(default_charset)) {
     621       47650 :                 return SG(default_charset);
     622             :         }
     623           0 :         return "";
     624             : }
     625             : 
     626       47880 : static char *get_input_encoding(void) {
     627       47880 :         if (PG(input_encoding) && PG(input_encoding)[0]) {
     628           0 :                 return PG(input_encoding);
     629       47880 :         } else if (SG(default_charset)) {
     630       47880 :                 return SG(default_charset);
     631             :         }
     632           0 :         return "";
     633             : }
     634             : 
     635       23942 : static char *get_output_encoding(void) {
     636       23942 :         if (PG(output_encoding) && PG(output_encoding)[0]) {
     637           0 :                 return PG(output_encoding);
     638       23942 :         } else if (SG(default_charset)) {
     639       23942 :                 return SG(default_charset);
     640             :         }
     641           0 :         return "";
     642             : }
     643             : 
     644             : 
     645             : /* {{{ allocators */
     646      395837 : static void *_php_mb_allocators_malloc(unsigned int sz)
     647             : {
     648      395837 :         return emalloc(sz);
     649             : }
     650             : 
     651       97599 : static void *_php_mb_allocators_realloc(void *ptr, unsigned int sz)
     652             : {
     653       97599 :         return erealloc(ptr, sz);
     654             : }
     655             : 
     656          53 : static void *_php_mb_allocators_calloc(unsigned int nelems, unsigned int szelem)
     657             : {
     658          53 :         return ecalloc(nelems, szelem);
     659             : }
     660             : 
     661      301352 : static void _php_mb_allocators_free(void *ptr)
     662             : {
     663      301352 :         efree(ptr);
     664      301352 : }
     665             : 
     666           0 : static void *_php_mb_allocators_pmalloc(unsigned int sz)
     667             : {
     668           0 :         return pemalloc(sz, 1);
     669             : }
     670             : 
     671           0 : static void *_php_mb_allocators_prealloc(void *ptr, unsigned int sz)
     672             : {
     673           0 :         return perealloc(ptr, sz, 1);
     674             : }
     675             : 
     676           0 : static void _php_mb_allocators_pfree(void *ptr)
     677             : {
     678           0 :         pefree(ptr, 1);
     679           0 : }
     680             : 
     681             : static mbfl_allocators _php_mb_allocators = {
     682             :         _php_mb_allocators_malloc,
     683             :         _php_mb_allocators_realloc,
     684             :         _php_mb_allocators_calloc,
     685             :         _php_mb_allocators_free,
     686             :         _php_mb_allocators_pmalloc,
     687             :         _php_mb_allocators_prealloc,
     688             :         _php_mb_allocators_pfree
     689             : };
     690             : /* }}} */
     691             : 
     692             : /* {{{ static sapi_post_entry mbstr_post_entries[] */
     693             : static sapi_post_entry mbstr_post_entries[] = {
     694             :         { DEFAULT_POST_CONTENT_TYPE, sizeof(DEFAULT_POST_CONTENT_TYPE)-1, sapi_read_standard_form_data, php_mb_post_handler },
     695             :         { MULTIPART_CONTENT_TYPE,    sizeof(MULTIPART_CONTENT_TYPE)-1,    NULL,                         rfc1867_post_handler },
     696             :         { NULL, 0, NULL, NULL }
     697             : };
     698             : /* }}} */
     699             : 
     700             : /* {{{ static int php_mb_parse_encoding_list()
     701             :  *  Return 0 if input contains any illegal encoding, otherwise 1.
     702             :  *  Even if any illegal encoding is detected the result may contain a list
     703             :  *  of parsed encodings.
     704             :  */
     705             : static int
     706      182840 : php_mb_parse_encoding_list(const char *value, size_t value_length, const mbfl_encoding ***return_list, size_t *return_size, int persistent)
     707             : {
     708      182840 :         int bauto, ret = SUCCESS;
     709             :         size_t n, size;
     710             :         char *p, *p1, *p2, *endp, *tmpstr;
     711             :         const mbfl_encoding **entry, **list;
     712             : 
     713      182840 :         list = NULL;
     714      182840 :         if (value == NULL || value_length <= 0) {
     715       23932 :                 if (return_list) {
     716       23932 :                         *return_list = NULL;
     717             :                 }
     718       23932 :                 if (return_size) {
     719       23932 :                         *return_size = 0;
     720             :                 }
     721       23932 :                 return FAILURE;
     722             :         } else {
     723             :                 /* copy the value string for work */
     724      158908 :                 if (value[0]=='"' && value[value_length-1]=='"' && value_length>2) {
     725           0 :                         tmpstr = (char *)estrndup(value+1, value_length-2);
     726           0 :                         value_length -= 2;
     727             :                 }
     728             :                 else
     729      158908 :                         tmpstr = (char *)estrndup(value, value_length);
     730      158908 :                 if (tmpstr == NULL) {
     731           0 :                         return FAILURE;
     732             :                 }
     733             :                 /* count the number of listed encoding names */
     734      158908 :                 endp = tmpstr + value_length;
     735      158908 :                 n = 1;
     736      158908 :                 p1 = tmpstr;
     737      317846 :                 while ((p2 = (char*)php_memnstr(p1, ",", 1, endp)) != NULL) {
     738          30 :                         p1 = p2 + 1;
     739          30 :                         n++;
     740             :                 }
     741      158908 :                 size = n + MBSTRG(default_detect_order_list_size);
     742             :                 /* make list */
     743      158908 :                 list = (const mbfl_encoding **)pecalloc(size, sizeof(mbfl_encoding*), persistent);
     744      158908 :                 if (list != NULL) {
     745      158908 :                         entry = list;
     746      158908 :                         n = 0;
     747      158908 :                         bauto = 0;
     748      158908 :                         p1 = tmpstr;
     749             :                         do {
     750      158938 :                                 p2 = p = (char*)php_memnstr(p1, ",", 1, endp);
     751      158938 :                                 if (p == NULL) {
     752      158908 :                                         p = endp;
     753             :                                 }
     754      158938 :                                 *p = '\0';
     755             :                                 /* trim spaces */
     756      317876 :                                 while (p1 < p && (*p1 == ' ' || *p1 == '\t')) {
     757           0 :                                         p1++;
     758             :                                 }
     759      158938 :                                 p--;
     760      317876 :                                 while (p > p1 && (*p == ' ' || *p == '\t')) {
     761           0 :                                         *p = '\0';
     762           0 :                                         p--;
     763             :                                 }
     764             :                                 /* convert to the encoding number and check encoding */
     765      158938 :                                 if (strcasecmp(p1, "auto") == 0) {
     766          13 :                                         if (!bauto) {
     767          13 :                                                 const enum mbfl_no_encoding *src = MBSTRG(default_detect_order_list);
     768          13 :                                                 const size_t identify_list_size = MBSTRG(default_detect_order_list_size);
     769             :                                                 size_t i;
     770          13 :                                                 bauto = 1;
     771          72 :                                                 for (i = 0; i < identify_list_size; i++) {
     772          59 :                                                         *entry++ = mbfl_no2encoding(*src++);
     773          59 :                                                         n++;
     774             :                                                 }
     775             :                                         }
     776             :                                 } else {
     777      158925 :                                         const mbfl_encoding *encoding = mbfl_name2encoding(p1);
     778      158925 :                                         if (encoding) {
     779      158906 :                                                 *entry++ = encoding;
     780      158906 :                                                 n++;
     781             :                                         } else {
     782          19 :                                                 ret = 0;
     783             :                                         }
     784             :                                 }
     785      158938 :                                 p1 = p2 + 1;
     786      158938 :                         } while (n < size && p2 != NULL);
     787      158908 :                         if (n > 0) {
     788      158889 :                                 if (return_list) {
     789      158889 :                                         *return_list = list;
     790             :                                 } else {
     791           0 :                                         pefree(list, persistent);
     792             :                                 }
     793             :                         } else {
     794          19 :                                 pefree(list, persistent);
     795          19 :                                 if (return_list) {
     796          19 :                                         *return_list = NULL;
     797             :                                 }
     798          19 :                                 ret = 0;
     799             :                         }
     800      158908 :                         if (return_size) {
     801      158908 :                                 *return_size = n;
     802             :                         }
     803             :                 } else {
     804           0 :                         if (return_list) {
     805           0 :                                 *return_list = NULL;
     806             :                         }
     807           0 :                         if (return_size) {
     808           0 :                                 *return_size = 0;
     809             :                         }
     810           0 :                         ret = 0;
     811             :                 }
     812      158908 :                 efree(tmpstr);
     813             :         }
     814             : 
     815      158908 :         return ret;
     816             : }
     817             : /* }}} */
     818             : 
     819             : /* {{{ static int php_mb_parse_encoding_array()
     820             :  *  Return 0 if input contains any illegal encoding, otherwise 1.
     821             :  *  Even if any illegal encoding is detected the result may contain a list
     822             :  *  of parsed encodings.
     823             :  */
     824             : static int
     825           5 : php_mb_parse_encoding_array(zval *array, const mbfl_encoding ***return_list, size_t *return_size, int persistent)
     826             : {
     827             :         zval *hash_entry;
     828             :         HashTable *target_hash;
     829           5 :         int i, n, size, bauto, ret = SUCCESS;
     830             :         const mbfl_encoding **list, **entry;
     831             : 
     832           5 :         list = NULL;
     833           5 :         if (Z_TYPE_P(array) == IS_ARRAY) {
     834           5 :                 target_hash = Z_ARRVAL_P(array);
     835           5 :                 i = zend_hash_num_elements(target_hash);
     836           5 :                 size = i + MBSTRG(default_detect_order_list_size);
     837           5 :                 list = (const mbfl_encoding **)pecalloc(size, sizeof(mbfl_encoding*), persistent);
     838           5 :                 if (list != NULL) {
     839           5 :                         entry = list;
     840           5 :                         bauto = 0;
     841           5 :                         n = 0;
     842          47 :                         ZEND_HASH_FOREACH_VAL(target_hash, hash_entry) {
     843          21 :                                 convert_to_string_ex(hash_entry);
     844          21 :                                 if (strcasecmp(Z_STRVAL_P(hash_entry), "auto") == 0) {
     845           0 :                                         if (!bauto) {
     846           0 :                                                 const enum mbfl_no_encoding *src = MBSTRG(default_detect_order_list);
     847           0 :                                                 const size_t identify_list_size = MBSTRG(default_detect_order_list_size);
     848             :                                                 size_t j;
     849             : 
     850           0 :                                                 bauto = 1;
     851           0 :                                                 for (j = 0; j < identify_list_size; j++) {
     852           0 :                                                         *entry++ = mbfl_no2encoding(*src++);
     853           0 :                                                         n++;
     854             :                                                 }
     855             :                                         }
     856             :                                 } else {
     857          21 :                                         const mbfl_encoding *encoding = mbfl_name2encoding(Z_STRVAL_P(hash_entry));
     858          21 :                                         if (encoding) {
     859          20 :                                                 *entry++ = encoding;
     860          20 :                                                 n++;
     861             :                                         } else {
     862           1 :                                                 ret = FAILURE;
     863             :                                         }
     864             :                                 }
     865          21 :                                 i--;
     866             :                         } ZEND_HASH_FOREACH_END();
     867           5 :                         if (n > 0) {
     868           5 :                                 if (return_list) {
     869           5 :                                         *return_list = list;
     870             :                                 } else {
     871           0 :                                         pefree(list, persistent);
     872             :                                 }
     873             :                         } else {
     874           0 :                                 pefree(list, persistent);
     875           0 :                                 if (return_list) {
     876           0 :                                         *return_list = NULL;
     877             :                                 }
     878           0 :                                 ret = FAILURE;
     879             :                         }
     880           5 :                         if (return_size) {
     881           5 :                                 *return_size = n;
     882             :                         }
     883             :                 } else {
     884           0 :                         if (return_list) {
     885           0 :                                 *return_list = NULL;
     886             :                         }
     887           0 :                         if (return_size) {
     888           0 :                                 *return_size = 0;
     889             :                         }
     890           0 :                         ret = FAILURE;
     891             :                 }
     892             :         }
     893             : 
     894           5 :         return ret;
     895             : }
     896             : /* }}} */
     897             : 
     898             : /* {{{ zend_multibyte interface */
     899      119794 : static const zend_encoding* php_mb_zend_encoding_fetcher(const char *encoding_name)
     900             : {
     901      119794 :         return (const zend_encoding*)mbfl_name2encoding(encoding_name);
     902             : }
     903             : 
     904          18 : static const char *php_mb_zend_encoding_name_getter(const zend_encoding *encoding)
     905             : {
     906          18 :         return ((const mbfl_encoding *)encoding)->name;
     907             : }
     908             : 
     909          46 : static int php_mb_zend_encoding_lexer_compatibility_checker(const zend_encoding *_encoding)
     910             : {
     911          46 :         const mbfl_encoding *encoding = (const mbfl_encoding*)_encoding;
     912          46 :         if (encoding->flag & MBFL_ENCTYPE_SBCS) {
     913           3 :                 return 1;
     914             :         }
     915          43 :         if ((encoding->flag & (MBFL_ENCTYPE_MBCS | MBFL_ENCTYPE_GL_UNSAFE)) == MBFL_ENCTYPE_MBCS) {
     916          36 :                 return 1;
     917             :         }
     918           7 :         return 0;
     919             : }
     920             : 
     921           3 : static const zend_encoding *php_mb_zend_encoding_detector(const unsigned char *arg_string, size_t arg_length, const zend_encoding **list, size_t list_size)
     922             : {
     923             :         mbfl_string string;
     924             : 
     925           3 :         if (!list) {
     926           0 :                 list = (const zend_encoding **)MBSTRG(current_detect_order_list);
     927           0 :                 list_size = MBSTRG(current_detect_order_list_size);
     928             :         }
     929             : 
     930           3 :         mbfl_string_init(&string);
     931           3 :         string.no_language = MBSTRG(language);
     932           3 :         string.val = (unsigned char *)arg_string;
     933           3 :         string.len = arg_length;
     934           3 :         return (const zend_encoding *) mbfl_identify_encoding2(&string, (const mbfl_encoding **)list, list_size, 0);
     935             : }
     936             : 
     937          87 : static size_t php_mb_zend_encoding_converter(unsigned char **to, size_t *to_length, const unsigned char *from, size_t from_length, const zend_encoding *encoding_to, const zend_encoding *encoding_from)
     938             : {
     939             :         mbfl_string string, result;
     940             :         mbfl_buffer_converter *convd;
     941             :         int status, loc;
     942             : 
     943             :         /* new encoding */
     944             :         /* initialize string */
     945          87 :         mbfl_string_init(&string);
     946          87 :         mbfl_string_init(&result);
     947          87 :         string.no_encoding = ((const mbfl_encoding*)encoding_from)->no_encoding;
     948          87 :         string.no_language = MBSTRG(language);
     949          87 :         string.val = (unsigned char*)from;
     950          87 :         string.len = from_length;
     951             : 
     952             :         /* initialize converter */
     953          87 :         convd = mbfl_buffer_converter_new2((const mbfl_encoding *)encoding_from, (const mbfl_encoding *)encoding_to, string.len);
     954          87 :         if (convd == NULL) {
     955           0 :                 return -1;
     956             :         }
     957          87 :         mbfl_buffer_converter_illegal_mode(convd, MBSTRG(current_filter_illegal_mode));
     958          87 :         mbfl_buffer_converter_illegal_substchar(convd, MBSTRG(current_filter_illegal_substchar));
     959             : 
     960             :         /* do it */
     961          87 :         status = mbfl_buffer_converter_feed2(convd, &string, &loc);
     962          87 :         if (status) {
     963           0 :                 mbfl_buffer_converter_delete(convd);
     964           0 :                 return (size_t)-1;
     965             :         }
     966             : 
     967          87 :         mbfl_buffer_converter_flush(convd);
     968          87 :         if (!mbfl_buffer_converter_result(convd, &result)) {
     969           0 :                 mbfl_buffer_converter_delete(convd);
     970           0 :                 return (size_t)-1;
     971             :         }
     972             : 
     973          87 :         *to = result.val;
     974          87 :         *to_length = result.len;
     975             : 
     976          87 :         mbfl_buffer_converter_delete(convd);
     977             : 
     978          87 :         return loc;
     979             : }
     980             : 
     981      143700 : static int php_mb_zend_encoding_list_parser(const char *encoding_list, size_t encoding_list_len, const zend_encoding ***return_list, size_t *return_size, int persistent)
     982             : {
     983      143700 :         return php_mb_parse_encoding_list(encoding_list, encoding_list_len, (const mbfl_encoding ***)return_list, return_size, persistent);
     984             : }
     985             : 
     986         169 : static const zend_encoding *php_mb_zend_internal_encoding_getter(void)
     987             : {
     988         169 :         return (const zend_encoding *)MBSTRG(internal_encoding);
     989             : }
     990             : 
     991       23904 : static int php_mb_zend_internal_encoding_setter(const zend_encoding *encoding)
     992             : {
     993       23904 :         MBSTRG(internal_encoding) = (const mbfl_encoding *)encoding;
     994       23904 :         return SUCCESS;
     995             : }
     996             : 
     997             : static zend_multibyte_functions php_mb_zend_multibyte_functions = {
     998             :         "mbstring",
     999             :         php_mb_zend_encoding_fetcher,
    1000             :         php_mb_zend_encoding_name_getter,
    1001             :         php_mb_zend_encoding_lexer_compatibility_checker,
    1002             :         php_mb_zend_encoding_detector,
    1003             :         php_mb_zend_encoding_converter,
    1004             :         php_mb_zend_encoding_list_parser,
    1005             :         php_mb_zend_internal_encoding_getter,
    1006             :         php_mb_zend_internal_encoding_setter
    1007             : };
    1008             : /* }}} */
    1009             : 
    1010             : static void *_php_mb_compile_regex(const char *pattern);
    1011             : static int _php_mb_match_regex(void *opaque, const char *str, size_t str_len);
    1012             : static void _php_mb_free_regex(void *opaque);
    1013             : 
    1014             : #if HAVE_ONIG
    1015             : /* {{{ _php_mb_compile_regex */
    1016       23954 : static void *_php_mb_compile_regex(const char *pattern)
    1017             : {
    1018             :         php_mb_regex_t *retval;
    1019             :         OnigErrorInfo err_info;
    1020             :         int err_code;
    1021             : 
    1022       47908 :         if ((err_code = onig_new(&retval,
    1023             :                         (const OnigUChar *)pattern,
    1024       23954 :                         (const OnigUChar *)pattern + strlen(pattern),
    1025             :                         ONIG_OPTION_IGNORECASE | ONIG_OPTION_DONT_CAPTURE_GROUP,
    1026             :                         ONIG_ENCODING_ASCII, &OnigSyntaxPerl, &err_info))) {
    1027             :                 OnigUChar err_str[ONIG_MAX_ERROR_MESSAGE_LEN];
    1028           0 :                 onig_error_code_to_str(err_str, err_code, err_info);
    1029           0 :                 php_error_docref(NULL, E_WARNING, "%s: %s", pattern, err_str);
    1030           0 :                 retval = NULL;
    1031             :         }
    1032       23954 :         return retval;
    1033             : }
    1034             : /* }}} */
    1035             : 
    1036             : /* {{{ _php_mb_match_regex */
    1037          12 : static int _php_mb_match_regex(void *opaque, const char *str, size_t str_len)
    1038             : {
    1039          12 :         return onig_search((php_mb_regex_t *)opaque, (const OnigUChar *)str,
    1040             :                         (const OnigUChar*)str + str_len, (const OnigUChar *)str,
    1041             :                         (const OnigUChar*)str + str_len, NULL, ONIG_OPTION_NONE) >= 0;
    1042             : }
    1043             : /* }}} */
    1044             : 
    1045             : /* {{{ _php_mb_free_regex */
    1046       23973 : static void _php_mb_free_regex(void *opaque)
    1047             : {
    1048       23973 :         onig_free((php_mb_regex_t *)opaque);
    1049       23973 : }
    1050             : /* }}} */
    1051             : #elif HAVE_PCRE || HAVE_BUNDLED_PCRE
    1052             : /* {{{ _php_mb_compile_regex */
    1053             : static void *_php_mb_compile_regex(const char *pattern)
    1054             : {
    1055             :         pcre *retval;
    1056             :         const char *err_str;
    1057             :         int err_offset;
    1058             : 
    1059             :         if (!(retval = pcre_compile(pattern,
    1060             :                         PCRE_CASELESS, &err_str, &err_offset, NULL))) {
    1061             :                 php_error_docref(NULL, E_WARNING, "%s (offset=%d): %s", pattern, err_offset, err_str);
    1062             :         }
    1063             :         return retval;
    1064             : }
    1065             : /* }}} */
    1066             : 
    1067             : /* {{{ _php_mb_match_regex */
    1068             : static int _php_mb_match_regex(void *opaque, const char *str, size_t str_len)
    1069             : {
    1070             :         return pcre_exec((pcre *)opaque, NULL, str, (int)str_len, 0,
    1071             :                         0, NULL, 0) >= 0;
    1072             : }
    1073             : /* }}} */
    1074             : 
    1075             : /* {{{ _php_mb_free_regex */
    1076             : static void _php_mb_free_regex(void *opaque)
    1077             : {
    1078             :         pcre_free(opaque);
    1079             : }
    1080             : /* }}} */
    1081             : #endif
    1082             : 
    1083             : /* {{{ php_mb_nls_get_default_detect_order_list */
    1084       23980 : static int php_mb_nls_get_default_detect_order_list(enum mbfl_no_language lang, enum mbfl_no_encoding **plist, size_t *plist_size)
    1085             : {
    1086             :         size_t i;
    1087             : 
    1088       23980 :         *plist = (enum mbfl_no_encoding *) php_mb_default_identify_list_neut;
    1089       23980 :         *plist_size = sizeof(php_mb_default_identify_list_neut) / sizeof(php_mb_default_identify_list_neut[0]);
    1090             : 
    1091      215646 :         for (i = 0; i < sizeof(php_mb_default_identify_list) / sizeof(php_mb_default_identify_list[0]); i++) {
    1092      215642 :                 if (php_mb_default_identify_list[i].lang == lang) {
    1093       23976 :                         *plist = (enum mbfl_no_encoding *)php_mb_default_identify_list[i].list;
    1094       23976 :                         *plist_size = php_mb_default_identify_list[i].list_size;
    1095       23976 :                         return 1;
    1096             :                 }
    1097             :         }
    1098           4 :         return 0;
    1099             : }
    1100             : /* }}} */
    1101             : 
    1102           3 : static char *php_mb_rfc1867_substring_conf(const zend_encoding *encoding, char *start, int len, char quote)
    1103             : {
    1104           3 :         char *result = emalloc(len + 2);
    1105           3 :         char *resp = result;
    1106             :         int i;
    1107             : 
    1108          19 :         for (i = 0; i < len && start[i] != quote; ++i) {
    1109          16 :                 if (start[i] == '\\' && (start[i + 1] == '\\' || (quote && start[i + 1] == quote))) {
    1110           0 :                         *resp++ = start[++i];
    1111             :                 } else {
    1112          16 :                         size_t j = php_mb_mbchar_bytes_ex(start+i, (const mbfl_encoding *)encoding);
    1113             : 
    1114          51 :                         while (j-- > 0 && i < len) {
    1115          19 :                                 *resp++ = start[i++];
    1116             :                         }
    1117          16 :                         --i;
    1118             :                 }
    1119             :         }
    1120             : 
    1121           3 :         *resp = '\0';
    1122           3 :         return result;
    1123             : }
    1124             : 
    1125           8 : static char *php_mb_rfc1867_getword(const zend_encoding *encoding, char **line, char stop) /* {{{ */
    1126             : {
    1127           8 :         char *pos = *line, quote;
    1128             :         char *res;
    1129             : 
    1130          72 :         while (*pos && *pos != stop) {
    1131          59 :                 if ((quote = *pos) == '"' || quote == '\'') {
    1132           3 :                         ++pos;
    1133          25 :                         while (*pos && *pos != quote) {
    1134          20 :                                 if (*pos == '\\' && pos[1] && pos[1] == quote) {
    1135           1 :                                         pos += 2;
    1136             :                                 } else {
    1137          18 :                                         ++pos;
    1138             :                                 }
    1139             :                         }
    1140           3 :                         if (*pos) {
    1141           2 :                                 ++pos;
    1142             :                         }
    1143             :                 } else {
    1144          53 :                         pos += php_mb_mbchar_bytes_ex(pos, (const mbfl_encoding *)encoding);
    1145             : 
    1146             :                 }
    1147             :         }
    1148           8 :         if (*pos == '\0') {
    1149           2 :                 res = estrdup(*line);
    1150           2 :                 *line += strlen(*line);
    1151           2 :                 return res;
    1152             :         }
    1153             : 
    1154           6 :         res = estrndup(*line, pos - *line);
    1155             : 
    1156          18 :         while (*pos == stop) {
    1157           6 :                 pos += php_mb_mbchar_bytes_ex(pos, (const mbfl_encoding *)encoding);
    1158             :         }
    1159             : 
    1160           6 :         *line = pos;
    1161           6 :         return res;
    1162             : }
    1163             : /* }}} */
    1164             : 
    1165           3 : static char *php_mb_rfc1867_getword_conf(const zend_encoding *encoding, char *str) /* {{{ */
    1166             : {
    1167           6 :         while (*str && isspace(*(unsigned char *)str)) {
    1168           0 :                 ++str;
    1169             :         }
    1170             : 
    1171           3 :         if (!*str) {
    1172           0 :                 return estrdup("");
    1173             :         }
    1174             : 
    1175           3 :         if (*str == '"' || *str == '\'') {
    1176           3 :                 char quote = *str;
    1177             : 
    1178           3 :                 str++;
    1179           3 :                 return php_mb_rfc1867_substring_conf(encoding, str, strlen(str), quote);
    1180             :         } else {
    1181           0 :                 char *strend = str;
    1182             : 
    1183           0 :                 while (*strend && !isspace(*(unsigned char *)strend)) {
    1184           0 :                         ++strend;
    1185             :                 }
    1186           0 :                 return php_mb_rfc1867_substring_conf(encoding, str, strend - str, 0);
    1187             :         }
    1188             : }
    1189             : /* }}} */
    1190             : 
    1191           1 : static char *php_mb_rfc1867_basename(const zend_encoding *encoding, char *filename) /* {{{ */
    1192             : {
    1193             :         char *s, *s2;
    1194           1 :         const size_t filename_len = strlen(filename);
    1195             : 
    1196             :         /* The \ check should technically be needed for win32 systems only where
    1197             :          * it is a valid path separator. However, IE in all it's wisdom always sends
    1198             :          * the full path of the file on the user's filesystem, which means that unless
    1199             :          * the user does basename() they get a bogus file name. Until IE's user base drops
    1200             :          * to nill or problem is fixed this code must remain enabled for all systems. */
    1201           1 :         s = php_mb_safe_strrchr_ex(filename, '\\', filename_len, (const mbfl_encoding *)encoding);
    1202           1 :         s2 = php_mb_safe_strrchr_ex(filename, '/', filename_len, (const mbfl_encoding *)encoding);
    1203             : 
    1204           1 :         if (s && s2) {
    1205           0 :                 if (s > s2) {
    1206           0 :                         return ++s;
    1207             :                 } else {
    1208           0 :                         return ++s2;
    1209             :                 }
    1210           1 :         } else if (s) {
    1211           0 :                 return ++s;
    1212           1 :         } else if (s2) {
    1213           0 :                 return ++s2;
    1214             :         } else {
    1215           1 :                 return filename;
    1216             :         }
    1217             : }
    1218             : /* }}} */
    1219             : 
    1220             : /* {{{ php.ini directive handler */
    1221             : /* {{{ static PHP_INI_MH(OnUpdate_mbstring_language) */
    1222       23980 : static PHP_INI_MH(OnUpdate_mbstring_language)
    1223             : {
    1224             :         enum mbfl_no_language no_language;
    1225             : 
    1226       23980 :         no_language = mbfl_name2no_language(ZSTR_VAL(new_value));
    1227       23980 :         if (no_language == mbfl_no_language_invalid) {
    1228           0 :                 MBSTRG(language) = mbfl_no_language_neutral;
    1229           0 :                 return FAILURE;
    1230             :         }
    1231       23980 :         MBSTRG(language) = no_language;
    1232       23980 :         php_mb_nls_get_default_detect_order_list(no_language, &MBSTRG(default_detect_order_list), &MBSTRG(default_detect_order_list_size));
    1233       23980 :         return SUCCESS;
    1234             : }
    1235             : /* }}} */
    1236             : 
    1237             : /* {{{ static PHP_INI_MH(OnUpdate_mbstring_detect_order) */
    1238       23950 : static PHP_INI_MH(OnUpdate_mbstring_detect_order)
    1239             : {
    1240             :         const mbfl_encoding **list;
    1241             :         size_t size;
    1242             : 
    1243       23950 :         if (!new_value) {
    1244       23948 :                 if (MBSTRG(detect_order_list)) {
    1245           0 :                         pefree(MBSTRG(detect_order_list), 1);
    1246             :                 }
    1247       23948 :                 MBSTRG(detect_order_list) = NULL;
    1248       23948 :                 MBSTRG(detect_order_list_size) = 0;
    1249       23948 :                 return SUCCESS;
    1250             :         }
    1251             : 
    1252           2 :         if (FAILURE == php_mb_parse_encoding_list(ZSTR_VAL(new_value), ZSTR_LEN(new_value), &list, &size, 1)) {
    1253           0 :                 return FAILURE;
    1254             :         }
    1255             : 
    1256           2 :         if (MBSTRG(detect_order_list)) {
    1257           0 :                 pefree(MBSTRG(detect_order_list), 1);
    1258             :         }
    1259           2 :         MBSTRG(detect_order_list) = list;
    1260           2 :         MBSTRG(detect_order_list_size) = size;
    1261           2 :         return SUCCESS;
    1262             : }
    1263             : /* }}} */
    1264             : 
    1265             : /* {{{ static PHP_INI_MH(OnUpdate_mbstring_http_input) */
    1266       23952 : static PHP_INI_MH(OnUpdate_mbstring_http_input)
    1267             : {
    1268             :         const mbfl_encoding **list;
    1269             :         size_t size;
    1270             : 
    1271       23952 :         if (!new_value || !ZSTR_VAL(new_value)) {
    1272       23940 :                 if (MBSTRG(http_input_list)) {
    1273           0 :                         pefree(MBSTRG(http_input_list), 1);
    1274             :                 }
    1275       23940 :                 if (SUCCESS == php_mb_parse_encoding_list(get_input_encoding(), strlen(get_input_encoding())+1, &list, &size, 1)) {
    1276       23940 :                         MBSTRG(http_input_list) = list;
    1277       23940 :                         MBSTRG(http_input_list_size) = size;
    1278       23940 :                         return SUCCESS;
    1279             :                 }
    1280           0 :                 MBSTRG(http_input_list) = NULL;
    1281           0 :                 MBSTRG(http_input_list_size) = 0;
    1282           0 :                 return SUCCESS;
    1283             :         }
    1284             : 
    1285          12 :         if (FAILURE == php_mb_parse_encoding_list(ZSTR_VAL(new_value), ZSTR_LEN(new_value), &list, &size, 1)) {
    1286           0 :                 return FAILURE;
    1287             :         }
    1288             : 
    1289          12 :         if (MBSTRG(http_input_list)) {
    1290           2 :                 pefree(MBSTRG(http_input_list), 1);
    1291             :         }
    1292          12 :         MBSTRG(http_input_list) = list;
    1293          12 :         MBSTRG(http_input_list_size) = size;
    1294             : 
    1295          12 :         if (stage & (PHP_INI_STAGE_ACTIVATE | PHP_INI_STAGE_RUNTIME)) {
    1296           1 :                 php_error_docref("ref.mbstring", E_DEPRECATED, "Use of mbstring.http_input is deprecated");
    1297             :         }
    1298             : 
    1299          12 :         return SUCCESS;
    1300             : }
    1301             : /* }}} */
    1302             : 
    1303             : /* {{{ static PHP_INI_MH(OnUpdate_mbstring_http_output) */
    1304       23952 : static PHP_INI_MH(OnUpdate_mbstring_http_output)
    1305             : {
    1306             :         const mbfl_encoding *encoding;
    1307             : 
    1308       47877 :         if (new_value == NULL || ZSTR_LEN(new_value) == 0) {
    1309       23942 :                 encoding = mbfl_name2encoding(get_output_encoding());
    1310       23942 :                 if (!encoding) {
    1311          17 :                         MBSTRG(http_output_encoding) = &mbfl_encoding_pass;
    1312          17 :                         MBSTRG(current_http_output_encoding) = &mbfl_encoding_pass;
    1313          17 :                         return SUCCESS;
    1314             :                 }
    1315             :         } else {
    1316          10 :                 encoding = mbfl_name2encoding(ZSTR_VAL(new_value));
    1317          10 :                 if (!encoding) {
    1318           0 :                         MBSTRG(http_output_encoding) = &mbfl_encoding_pass;
    1319           0 :                         MBSTRG(current_http_output_encoding) = &mbfl_encoding_pass;
    1320           0 :                         return FAILURE;
    1321             :                 }
    1322             :         }
    1323       23935 :         MBSTRG(http_output_encoding) = encoding;
    1324       23935 :         MBSTRG(current_http_output_encoding) = encoding;
    1325             : 
    1326       23935 :         if (stage & (PHP_INI_STAGE_ACTIVATE | PHP_INI_STAGE_RUNTIME)) {
    1327           1 :                 php_error_docref("ref.mbstring", E_DEPRECATED, "Use of mbstring.http_output is deprecated");
    1328             :         }
    1329             : 
    1330       23935 :         return SUCCESS;
    1331             : }
    1332             : /* }}} */
    1333             : 
    1334             : /* {{{ static _php_mb_ini_mbstring_internal_encoding_set */
    1335       71836 : int _php_mb_ini_mbstring_internal_encoding_set(const char *new_value, uint new_value_length)
    1336             : {
    1337             :         const mbfl_encoding *encoding;
    1338             : 
    1339       71836 :         if (!new_value || !new_value_length || !(encoding = mbfl_name2encoding(new_value))) {
    1340             :                 /* falls back to UTF-8 if an unknown encoding name is given */
    1341       47681 :                 encoding = mbfl_no2encoding(mbfl_no_encoding_utf8);
    1342             :         }
    1343       71836 :         MBSTRG(internal_encoding) = encoding;
    1344       71836 :         MBSTRG(current_internal_encoding) = encoding;
    1345             : #if HAVE_MBREGEX
    1346             :         {
    1347       71836 :                 const char *enc_name = new_value;
    1348       71836 :                 if (FAILURE == php_mb_regex_set_default_mbctype(enc_name)) {
    1349             :                         /* falls back to UTF-8 if an unknown encoding name is given */
    1350       47746 :                         enc_name = "UTF-8";
    1351       47746 :                         php_mb_regex_set_default_mbctype(enc_name);
    1352             :                 }
    1353       71836 :                 php_mb_regex_set_mbctype(new_value);
    1354             :         }
    1355             : #endif
    1356       71836 :         return SUCCESS;
    1357             : }
    1358             : /* }}} */
    1359             : 
    1360             : /* {{{ static PHP_INI_MH(OnUpdate_mbstring_internal_encoding) */
    1361       23954 : static PHP_INI_MH(OnUpdate_mbstring_internal_encoding)
    1362             : {
    1363       23954 :         if (stage & (PHP_INI_STAGE_ACTIVATE | PHP_INI_STAGE_RUNTIME)) {
    1364           2 :                 php_error_docref("ref.mbstring", E_DEPRECATED, "Use of mbstring.internal_encoding is deprecated");
    1365             :         }
    1366             : 
    1367       23954 :         if (OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage) == FAILURE) {
    1368           0 :                 return FAILURE;
    1369             :         }
    1370             : 
    1371       23954 :         if (stage & (PHP_INI_STAGE_STARTUP | PHP_INI_STAGE_SHUTDOWN | PHP_INI_STAGE_RUNTIME)) {
    1372       23952 :                 if (new_value && ZSTR_LEN(new_value)) {
    1373         111 :                         return _php_mb_ini_mbstring_internal_encoding_set(ZSTR_VAL(new_value), ZSTR_LEN(new_value));
    1374             :                 } else {
    1375       23841 :                         return _php_mb_ini_mbstring_internal_encoding_set(get_internal_encoding(), strlen(get_internal_encoding())+1);
    1376             :                 }
    1377             :         } else {
    1378             :                 /* the corresponding mbstring globals needs to be set according to the
    1379             :                  * ini value in the later stage because it never falls back to the
    1380             :                  * default value if 1. no value for mbstring.internal_encoding is given,
    1381             :                  * 2. mbstring.language directive is processed in per-dir or runtime
    1382             :                  * context and 3. call to the handler for mbstring.language is done
    1383             :                  * after mbstring.internal_encoding is handled. */
    1384           2 :                 return SUCCESS;
    1385             :         }
    1386             : }
    1387             : /* }}} */
    1388             : 
    1389             : /* {{{ static PHP_INI_MH(OnUpdate_mbstring_substitute_character) */
    1390       23950 : static PHP_INI_MH(OnUpdate_mbstring_substitute_character)
    1391             : {
    1392             :         int c;
    1393       23950 :         char *endptr = NULL;
    1394             : 
    1395       23950 :         if (new_value != NULL) {
    1396           2 :                 if (strcasecmp("none", ZSTR_VAL(new_value)) == 0) {
    1397           0 :                         MBSTRG(filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE;
    1398           0 :                         MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE;
    1399           2 :                 } else if (strcasecmp("long", ZSTR_VAL(new_value)) == 0) {
    1400           0 :                         MBSTRG(filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_LONG;
    1401           0 :                         MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_LONG;
    1402           2 :                 } else if (strcasecmp("entity", ZSTR_VAL(new_value)) == 0) {
    1403           0 :                         MBSTRG(filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_ENTITY;
    1404           0 :                         MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_ENTITY;
    1405             :                 } else {
    1406           2 :                         MBSTRG(filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR;
    1407           2 :                         MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR;
    1408           2 :                         if (ZSTR_LEN(new_value) > 0) {
    1409           2 :                                 c = strtol(ZSTR_VAL(new_value), &endptr, 0);
    1410           2 :                                 if (*endptr == '\0') {
    1411           2 :                                         MBSTRG(filter_illegal_substchar) = c;
    1412           2 :                                         MBSTRG(current_filter_illegal_substchar) = c;
    1413             :                                 }
    1414             :                         }
    1415             :                 }
    1416             :         } else {
    1417       23948 :                 MBSTRG(filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR;
    1418       23948 :                 MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR;
    1419       23948 :                 MBSTRG(filter_illegal_substchar) = 0x3f;        /* '?' */
    1420       23948 :                 MBSTRG(current_filter_illegal_substchar) = 0x3f;        /* '?' */
    1421             :         }
    1422             : 
    1423       23950 :         return SUCCESS;
    1424             : }
    1425             : /* }}} */
    1426             : 
    1427             : /* {{{ static PHP_INI_MH(OnUpdate_mbstring_encoding_translation) */
    1428       23950 : static PHP_INI_MH(OnUpdate_mbstring_encoding_translation)
    1429             : {
    1430       23950 :         if (new_value == NULL) {
    1431           0 :                 return FAILURE;
    1432             :         }
    1433             : 
    1434       23950 :         OnUpdateBool(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
    1435             : 
    1436       23950 :         if (MBSTRG(encoding_translation)) {
    1437          14 :                 sapi_unregister_post_entry(php_post_entries);
    1438          14 :                 sapi_register_post_entries(mbstr_post_entries);
    1439             :         } else {
    1440       23936 :                 sapi_unregister_post_entry(mbstr_post_entries);
    1441       23936 :                 sapi_register_post_entries(php_post_entries);
    1442             :         }
    1443             : 
    1444       23950 :         return SUCCESS;
    1445             : }
    1446             : /* }}} */
    1447             : 
    1448             : /* {{{ static PHP_INI_MH(OnUpdate_mbstring_http_output_conv_mimetypes */
    1449       23954 : static PHP_INI_MH(OnUpdate_mbstring_http_output_conv_mimetypes)
    1450             : {
    1451             :         zend_string *tmp;
    1452       23954 :         void *re = NULL;
    1453             : 
    1454       23954 :         if (!new_value) {
    1455           0 :                 new_value = entry->orig_value;
    1456             :         }
    1457       23954 :         tmp = php_trim(new_value, NULL, 0, 3);
    1458             : 
    1459       23954 :         if (ZSTR_LEN(tmp) > 0) {
    1460       23954 :                 if (!(re = _php_mb_compile_regex(ZSTR_VAL(tmp)))) {
    1461             :                         zend_string_release(tmp);
    1462           0 :                         return FAILURE;
    1463             :                 }
    1464             :         }
    1465             : 
    1466       23954 :         if (MBSTRG(http_output_conv_mimetypes)) {
    1467           4 :                 _php_mb_free_regex(MBSTRG(http_output_conv_mimetypes));
    1468             :         }
    1469             : 
    1470       23954 :         MBSTRG(http_output_conv_mimetypes) = re;
    1471             : 
    1472             :         zend_string_release(tmp);
    1473       23954 :         return SUCCESS;
    1474             : }
    1475             : /* }}} */
    1476             : /* }}} */
    1477             : 
    1478             : /* {{{ php.ini directive registration */
    1479             : PHP_INI_BEGIN()
    1480             :         PHP_INI_ENTRY("mbstring.language", "neutral", PHP_INI_ALL, OnUpdate_mbstring_language)
    1481             :         PHP_INI_ENTRY("mbstring.detect_order", NULL, PHP_INI_ALL, OnUpdate_mbstring_detect_order)
    1482             :         PHP_INI_ENTRY("mbstring.http_input", NULL, PHP_INI_ALL, OnUpdate_mbstring_http_input)
    1483             :         PHP_INI_ENTRY("mbstring.http_output", NULL, PHP_INI_ALL, OnUpdate_mbstring_http_output)
    1484             :         STD_PHP_INI_ENTRY("mbstring.internal_encoding", NULL, PHP_INI_ALL, OnUpdate_mbstring_internal_encoding, internal_encoding_name, zend_mbstring_globals, mbstring_globals)
    1485             :         PHP_INI_ENTRY("mbstring.substitute_character", NULL, PHP_INI_ALL, OnUpdate_mbstring_substitute_character)
    1486             :         STD_PHP_INI_ENTRY("mbstring.func_overload", "0",
    1487             :         PHP_INI_SYSTEM, OnUpdateLong, func_overload, zend_mbstring_globals, mbstring_globals)
    1488             : 
    1489             :         STD_PHP_INI_BOOLEAN("mbstring.encoding_translation", "0",
    1490             :                 PHP_INI_SYSTEM | PHP_INI_PERDIR,
    1491             :                 OnUpdate_mbstring_encoding_translation,
    1492             :                 encoding_translation, zend_mbstring_globals, mbstring_globals)
    1493             :         PHP_INI_ENTRY("mbstring.http_output_conv_mimetypes",
    1494             :                 "^(text/|application/xhtml\\+xml)",
    1495             :                 PHP_INI_ALL,
    1496             :                 OnUpdate_mbstring_http_output_conv_mimetypes)
    1497             : 
    1498             :         STD_PHP_INI_BOOLEAN("mbstring.strict_detection", "0",
    1499             :                 PHP_INI_ALL,
    1500             :                 OnUpdateLong,
    1501             :                 strict_detection, zend_mbstring_globals, mbstring_globals)
    1502             : PHP_INI_END()
    1503             : /* }}} */
    1504             : 
    1505             : /* {{{ module global initialize handler */
    1506       23950 : static PHP_GINIT_FUNCTION(mbstring)
    1507             : {
    1508             : #if defined(COMPILE_DL_MBSTRING) && defined(ZTS)
    1509             : ZEND_TSRMLS_CACHE_UPDATE();
    1510             : #endif
    1511             : 
    1512       23950 :         mbstring_globals->language = mbfl_no_language_uni;
    1513       23950 :         mbstring_globals->internal_encoding = NULL;
    1514       23950 :         mbstring_globals->current_internal_encoding = mbstring_globals->internal_encoding;
    1515       23950 :         mbstring_globals->http_output_encoding = &mbfl_encoding_pass;
    1516       23950 :         mbstring_globals->current_http_output_encoding = &mbfl_encoding_pass;
    1517       23950 :         mbstring_globals->http_input_identify = NULL;
    1518       23950 :         mbstring_globals->http_input_identify_get = NULL;
    1519       23950 :         mbstring_globals->http_input_identify_post = NULL;
    1520       23950 :         mbstring_globals->http_input_identify_cookie = NULL;
    1521       23950 :         mbstring_globals->http_input_identify_string = NULL;
    1522       23950 :         mbstring_globals->http_input_list = NULL;
    1523       23950 :         mbstring_globals->http_input_list_size = 0;
    1524       23950 :         mbstring_globals->detect_order_list = NULL;
    1525       23950 :         mbstring_globals->detect_order_list_size = 0;
    1526       23950 :         mbstring_globals->current_detect_order_list = NULL;
    1527       23950 :         mbstring_globals->current_detect_order_list_size = 0;
    1528       23950 :         mbstring_globals->default_detect_order_list = (enum mbfl_no_encoding *) php_mb_default_identify_list_neut;
    1529       23950 :         mbstring_globals->default_detect_order_list_size = sizeof(php_mb_default_identify_list_neut) / sizeof(php_mb_default_identify_list_neut[0]);
    1530       23950 :         mbstring_globals->filter_illegal_mode = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR;
    1531       23950 :         mbstring_globals->filter_illegal_substchar = 0x3f;   /* '?' */
    1532       23950 :         mbstring_globals->current_filter_illegal_mode = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR;
    1533       23950 :         mbstring_globals->current_filter_illegal_substchar = 0x3f;   /* '?' */
    1534       23950 :         mbstring_globals->illegalchars = 0;
    1535       23950 :         mbstring_globals->func_overload = 0;
    1536       23950 :         mbstring_globals->encoding_translation = 0;
    1537       23950 :         mbstring_globals->strict_detection = 0;
    1538       23950 :         mbstring_globals->outconv = NULL;
    1539       23950 :         mbstring_globals->http_output_conv_mimetypes = NULL;
    1540             : #if HAVE_MBREGEX
    1541       23950 :         mbstring_globals->mb_regex_globals = php_mb_regex_globals_alloc();
    1542             : #endif
    1543       23950 : }
    1544             : /* }}} */
    1545             : 
    1546             : /* {{{ PHP_GSHUTDOWN_FUNCTION */
    1547       23969 : static PHP_GSHUTDOWN_FUNCTION(mbstring)
    1548             : {
    1549       23969 :         if (mbstring_globals->http_input_list) {
    1550       23952 :                 free(mbstring_globals->http_input_list);
    1551             :         }
    1552       23969 :         if (mbstring_globals->detect_order_list) {
    1553           2 :                 free(mbstring_globals->detect_order_list);
    1554             :         }
    1555       23969 :         if (mbstring_globals->http_output_conv_mimetypes) {
    1556       23969 :                 _php_mb_free_regex(mbstring_globals->http_output_conv_mimetypes);
    1557             :         }
    1558             : #if HAVE_MBREGEX
    1559       23969 :         php_mb_regex_globals_free(mbstring_globals->mb_regex_globals);
    1560             : #endif
    1561       23969 : }
    1562             : /* }}} */
    1563             : 
    1564             : /* {{{ PHP_MINIT_FUNCTION(mbstring) */
    1565       23950 : PHP_MINIT_FUNCTION(mbstring)
    1566             : {
    1567             : #if defined(COMPILE_DL_MBSTRING) && defined(ZTS)
    1568             : ZEND_TSRMLS_CACHE_UPDATE();
    1569             : #endif
    1570       23950 :         __mbfl_allocators = &_php_mb_allocators;
    1571             : 
    1572       23950 :         REGISTER_INI_ENTRIES();
    1573             : 
    1574             :         /* This is a global handler. Should not be set in a per-request handler. */
    1575       23950 :         sapi_register_treat_data(mbstr_treat_data);
    1576             : 
    1577             :         /* Post handlers are stored in the thread-local context. */
    1578       23950 :         if (MBSTRG(encoding_translation)) {
    1579          14 :                 sapi_register_post_entries(mbstr_post_entries);
    1580             :         }
    1581             : 
    1582       23950 :         REGISTER_LONG_CONSTANT("MB_OVERLOAD_MAIL", MB_OVERLOAD_MAIL, CONST_CS | CONST_PERSISTENT);
    1583       23950 :         REGISTER_LONG_CONSTANT("MB_OVERLOAD_STRING", MB_OVERLOAD_STRING, CONST_CS | CONST_PERSISTENT);
    1584       23950 :         REGISTER_LONG_CONSTANT("MB_OVERLOAD_REGEX", MB_OVERLOAD_REGEX, CONST_CS | CONST_PERSISTENT);
    1585             : 
    1586       23950 :         REGISTER_LONG_CONSTANT("MB_CASE_UPPER", PHP_UNICODE_CASE_UPPER, CONST_CS | CONST_PERSISTENT);
    1587       23950 :         REGISTER_LONG_CONSTANT("MB_CASE_LOWER", PHP_UNICODE_CASE_LOWER, CONST_CS | CONST_PERSISTENT);
    1588       23950 :         REGISTER_LONG_CONSTANT("MB_CASE_TITLE", PHP_UNICODE_CASE_TITLE, CONST_CS | CONST_PERSISTENT);
    1589             : 
    1590             : #if HAVE_MBREGEX
    1591       23950 :         PHP_MINIT(mb_regex) (INIT_FUNC_ARGS_PASSTHRU);
    1592             : #endif
    1593             : 
    1594       23950 :         if (FAILURE == zend_multibyte_set_functions(&php_mb_zend_multibyte_functions)) {
    1595           0 :                 return FAILURE;
    1596             :         }
    1597             : 
    1598       23950 :         php_rfc1867_set_multibyte_callbacks(
    1599             :                 php_mb_encoding_translation,
    1600             :                 php_mb_gpc_get_detect_order,
    1601             :                 php_mb_gpc_set_input_encoding,
    1602             :                 php_mb_rfc1867_getword,
    1603             :                 php_mb_rfc1867_getword_conf,
    1604             :                 php_mb_rfc1867_basename);
    1605             : 
    1606       23950 :         return SUCCESS;
    1607             : }
    1608             : /* }}} */
    1609             : 
    1610             : /* {{{ PHP_MSHUTDOWN_FUNCTION(mbstring) */
    1611       23969 : PHP_MSHUTDOWN_FUNCTION(mbstring)
    1612             : {
    1613       23969 :         UNREGISTER_INI_ENTRIES();
    1614             : 
    1615       23969 :         zend_multibyte_restore_functions();
    1616             : 
    1617             : #if HAVE_MBREGEX
    1618       23969 :         PHP_MSHUTDOWN(mb_regex) (INIT_FUNC_ARGS_PASSTHRU);
    1619             : #endif
    1620             : 
    1621       23969 :         return SUCCESS;
    1622             : }
    1623             : /* }}} */
    1624             : 
    1625             : /* {{{ PHP_RINIT_FUNCTION(mbstring) */
    1626       23904 : PHP_RINIT_FUNCTION(mbstring)
    1627             : {
    1628             :         zend_function *func, *orig;
    1629             :         const struct mb_overload_def *p;
    1630             : 
    1631       23904 :         MBSTRG(current_internal_encoding) = MBSTRG(internal_encoding);
    1632       23904 :         MBSTRG(current_http_output_encoding) = MBSTRG(http_output_encoding);
    1633       23904 :         MBSTRG(current_filter_illegal_mode) = MBSTRG(filter_illegal_mode);
    1634       23904 :         MBSTRG(current_filter_illegal_substchar) = MBSTRG(filter_illegal_substchar);
    1635             : 
    1636       23904 :         MBSTRG(illegalchars) = 0;
    1637             : 
    1638       23904 :         php_mb_populate_current_detect_order_list();
    1639             : 
    1640             :         /* override original function. */
    1641       23904 :         if (MBSTRG(func_overload)){
    1642          10 :                 p = &(mb_ovld[0]);
    1643             : 
    1644          10 :                 CG(compiler_options) |= ZEND_COMPILE_NO_BUILTIN_STRLEN;
    1645         150 :                 while (p->type > 0) {
    1646         256 :                         if ((MBSTRG(func_overload) & p->type) == p->type &&
    1647         126 :                                 !zend_hash_str_exists(EG(function_table), p->save_func, strlen(p->save_func))
    1648             :                         ) {
    1649         252 :                                 func = zend_hash_str_find_ptr(EG(function_table), p->ovld_func, strlen(p->ovld_func));
    1650             : 
    1651         252 :                                 if ((orig = zend_hash_str_find_ptr(EG(function_table), p->orig_func, strlen(p->orig_func))) == NULL) {
    1652           0 :                                         php_error_docref("ref.mbstring", E_WARNING, "mbstring couldn't find function %s.", p->orig_func);
    1653           0 :                                         return FAILURE;
    1654             :                                 } else {
    1655             :                                         ZEND_ASSERT(orig->type == ZEND_INTERNAL_FUNCTION);
    1656         126 :                                         zend_hash_str_add_mem(EG(function_table), p->save_func, strlen(p->save_func), orig, sizeof(zend_internal_function));
    1657         126 :                                         function_add_ref(orig);
    1658             : 
    1659         252 :                                         if (zend_hash_str_update_mem(EG(function_table), p->orig_func, strlen(p->orig_func), func, sizeof(zend_internal_function)) == NULL) {
    1660           0 :                                                 php_error_docref("ref.mbstring", E_WARNING, "mbstring couldn't replace function %s.", p->orig_func);
    1661           0 :                                                 return FAILURE;
    1662             :                                         }
    1663             : 
    1664         126 :                                         function_add_ref(func);
    1665             :                                 }
    1666             :                         }
    1667         130 :                         p++;
    1668             :                 }
    1669             :         }
    1670             : #if HAVE_MBREGEX
    1671       23904 :         PHP_RINIT(mb_regex) (INIT_FUNC_ARGS_PASSTHRU);
    1672             : #endif
    1673       23904 :         zend_multibyte_set_internal_encoding((const zend_encoding *)MBSTRG(internal_encoding));
    1674             : 
    1675       23904 :         return SUCCESS;
    1676             : }
    1677             : /* }}} */
    1678             : 
    1679             : /* {{{ PHP_RSHUTDOWN_FUNCTION(mbstring) */
    1680       23925 : PHP_RSHUTDOWN_FUNCTION(mbstring)
    1681             : {
    1682             :         const struct mb_overload_def *p;
    1683             :         zend_function *orig;
    1684             : 
    1685       23925 :         if (MBSTRG(current_detect_order_list) != NULL) {
    1686       23925 :                 efree(MBSTRG(current_detect_order_list));
    1687       23925 :                 MBSTRG(current_detect_order_list) = NULL;
    1688       23925 :                 MBSTRG(current_detect_order_list_size) = 0;
    1689             :         }
    1690       23925 :         if (MBSTRG(outconv) != NULL) {
    1691           0 :                 MBSTRG(illegalchars) += mbfl_buffer_illegalchars(MBSTRG(outconv));
    1692           0 :                 mbfl_buffer_converter_delete(MBSTRG(outconv));
    1693           0 :                 MBSTRG(outconv) = NULL;
    1694             :         }
    1695             : 
    1696             :         /* clear http input identification. */
    1697       23925 :         MBSTRG(http_input_identify) = NULL;
    1698       23925 :         MBSTRG(http_input_identify_post) = NULL;
    1699       23925 :         MBSTRG(http_input_identify_get) = NULL;
    1700       23925 :         MBSTRG(http_input_identify_cookie) = NULL;
    1701       23925 :         MBSTRG(http_input_identify_string) = NULL;
    1702             : 
    1703             :         /*  clear overloaded function. */
    1704       23925 :         if (MBSTRG(func_overload)){
    1705          10 :                 p = &(mb_ovld[0]);
    1706         150 :                 while (p->type > 0) {
    1707         256 :                         if ((MBSTRG(func_overload) & p->type) == p->type &&
    1708         126 :                                 (orig = zend_hash_str_find_ptr(EG(function_table), p->save_func, strlen(p->save_func)))) {
    1709             : 
    1710         126 :                                 zend_hash_str_update_mem(EG(function_table), p->orig_func, strlen(p->orig_func), orig, sizeof(zend_internal_function));
    1711         126 :                                 function_add_ref(orig);
    1712         126 :                                 zend_hash_str_del(EG(function_table), p->save_func, strlen(p->save_func));
    1713             :                         }
    1714         130 :                         p++;
    1715             :                 }
    1716          10 :                 CG(compiler_options) &= ~ZEND_COMPILE_NO_BUILTIN_STRLEN;
    1717             :         }
    1718             : 
    1719             : #if HAVE_MBREGEX
    1720       23925 :         PHP_RSHUTDOWN(mb_regex) (INIT_FUNC_ARGS_PASSTHRU);
    1721             : #endif
    1722             : 
    1723       23925 :         return SUCCESS;
    1724             : }
    1725             : /* }}} */
    1726             : 
    1727             : /* {{{ PHP_MINFO_FUNCTION(mbstring) */
    1728         143 : PHP_MINFO_FUNCTION(mbstring)
    1729             : {
    1730         143 :         php_info_print_table_start();
    1731         143 :         php_info_print_table_row(2, "Multibyte Support", "enabled");
    1732         143 :         php_info_print_table_row(2, "Multibyte string engine", "libmbfl");
    1733         143 :         php_info_print_table_row(2, "HTTP input encoding translation", MBSTRG(encoding_translation) ? "enabled": "disabled");
    1734             :         {
    1735             :                 char tmp[256];
    1736         143 :                 snprintf(tmp, sizeof(tmp), "%d.%d.%d", MBFL_VERSION_MAJOR, MBFL_VERSION_MINOR, MBFL_VERSION_TEENY);
    1737         143 :                 php_info_print_table_row(2, "libmbfl version", tmp);
    1738             :         }
    1739             : #if HAVE_ONIG
    1740             :         {
    1741             :                 char tmp[256];
    1742         143 :                 snprintf(tmp, sizeof(tmp), "%d.%d.%d", ONIGURUMA_VERSION_MAJOR, ONIGURUMA_VERSION_MINOR, ONIGURUMA_VERSION_TEENY);
    1743         143 :                 php_info_print_table_row(2, "oniguruma version", tmp);
    1744             :         }
    1745             : #endif
    1746         143 :         php_info_print_table_end();
    1747             : 
    1748         143 :         php_info_print_table_start();
    1749         143 :         php_info_print_table_header(1, "mbstring extension makes use of \"streamable kanji code filter and converter\", which is distributed under the GNU Lesser General Public License version 2.1.");
    1750         143 :         php_info_print_table_end();
    1751             : 
    1752             : #if HAVE_MBREGEX
    1753         143 :         PHP_MINFO(mb_regex)(ZEND_MODULE_INFO_FUNC_ARGS_PASSTHRU);
    1754             : #endif
    1755             : 
    1756         143 :         DISPLAY_INI_ENTRIES();
    1757         143 : }
    1758             : /* }}} */
    1759             : 
    1760             : /* {{{ proto string mb_language([string language])
    1761             :    Sets the current language or Returns the current language as a string */
    1762          30 : PHP_FUNCTION(mb_language)
    1763             : {
    1764          30 :         zend_string *name = NULL;
    1765             : 
    1766          30 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S", &name) == FAILURE) {
    1767           0 :                 return;
    1768             :         }
    1769          30 :         if (name == NULL) {
    1770          30 :                 RETVAL_STRING((char *)mbfl_no_language2name(MBSTRG(language)));
    1771             :         } else {
    1772          15 :                 zend_string *ini_name = zend_string_init("mbstring.language", sizeof("mbstring.language") - 1, 0);
    1773          15 :                 if (FAILURE == zend_alter_ini_entry(ini_name, name, PHP_INI_USER, PHP_INI_STAGE_RUNTIME)) {
    1774           0 :                         php_error_docref(NULL, E_WARNING, "Unknown language \"%s\"", ZSTR_VAL(name));
    1775           0 :                         RETVAL_FALSE;
    1776             :                 } else {
    1777          15 :                         RETVAL_TRUE;
    1778             :                 }
    1779             :                 zend_string_release(ini_name);
    1780             :         }
    1781             : }
    1782             : /* }}} */
    1783             : 
    1784             : /* {{{ proto string mb_internal_encoding([string encoding])
    1785             :    Sets the current internal encoding or Returns the current internal encoding as a string */
    1786         320 : PHP_FUNCTION(mb_internal_encoding)
    1787             : {
    1788         320 :         const char *name = NULL;
    1789             :         size_t name_len;
    1790             :         const mbfl_encoding *encoding;
    1791             : 
    1792         320 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &name, &name_len) == FAILURE) {
    1793           4 :                 return;
    1794             :         }
    1795         316 :         if (name == NULL) {
    1796         143 :                 name = MBSTRG(current_internal_encoding) ? MBSTRG(current_internal_encoding)->name: NULL;
    1797         143 :                 if (name != NULL) {
    1798         286 :                         RETURN_STRING(name);
    1799             :                 } else {
    1800           0 :                         RETURN_FALSE;
    1801             :                 }
    1802             :         } else {
    1803         173 :                 encoding = mbfl_name2encoding(name);
    1804         173 :                 if (!encoding) {
    1805          21 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", name);
    1806          21 :                         RETURN_FALSE;
    1807             :                 } else {
    1808         152 :                         MBSTRG(current_internal_encoding) = encoding;
    1809         152 :                         RETURN_TRUE;
    1810             :                 }
    1811             :         }
    1812             : }
    1813             : /* }}} */
    1814             : 
    1815             : /* {{{ proto mixed mb_http_input([string type])
    1816             :    Returns the input encoding */
    1817           2 : PHP_FUNCTION(mb_http_input)
    1818             : {
    1819           2 :         char *typ = NULL;
    1820             :         size_t typ_len;
    1821             :         int retname;
    1822             :         char *list, *temp;
    1823           2 :         const mbfl_encoding *result = NULL;
    1824             : 
    1825           2 :         retname = 1;
    1826           2 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &typ, &typ_len) == FAILURE) {
    1827           0 :                 return;
    1828             :         }
    1829           2 :         if (typ == NULL) {
    1830           1 :                 result = MBSTRG(http_input_identify);
    1831             :         } else {
    1832           1 :                 switch (*typ) {
    1833             :                 case 'G':
    1834             :                 case 'g':
    1835           0 :                         result = MBSTRG(http_input_identify_get);
    1836           0 :                         break;
    1837             :                 case 'P':
    1838             :                 case 'p':
    1839           0 :                         result = MBSTRG(http_input_identify_post);
    1840           0 :                         break;
    1841             :                 case 'C':
    1842             :                 case 'c':
    1843           0 :                         result = MBSTRG(http_input_identify_cookie);
    1844           0 :                         break;
    1845             :                 case 'S':
    1846             :                 case 's':
    1847           0 :                         result = MBSTRG(http_input_identify_string);
    1848           0 :                         break;
    1849             :                 case 'I':
    1850             :                 case 'i':
    1851             :                         {
    1852           0 :                                 const mbfl_encoding **entry = MBSTRG(http_input_list);
    1853           0 :                                 const size_t n = MBSTRG(http_input_list_size);
    1854             :                                 size_t i;
    1855           0 :                                 array_init(return_value);
    1856           0 :                                 for (i = 0; i < n; i++) {
    1857           0 :                                         add_next_index_string(return_value, (*entry)->name);
    1858           0 :                                         entry++;
    1859             :                                 }
    1860           0 :                                 retname = 0;
    1861             :                         }
    1862           0 :                         break;
    1863             :                 case 'L':
    1864             :                 case 'l':
    1865             :                         {
    1866           1 :                                 const mbfl_encoding **entry = MBSTRG(http_input_list);
    1867           1 :                                 const size_t n = MBSTRG(http_input_list_size);
    1868             :                                 size_t i;
    1869           1 :                                 list = NULL;
    1870           2 :                                 for (i = 0; i < n; i++) {
    1871           1 :                                         if (list) {
    1872           0 :                                                 temp = list;
    1873           0 :                                                 spprintf(&list, 0, "%s,%s", temp, (*entry)->name);
    1874           0 :                                                 efree(temp);
    1875           0 :                                                 if (!list) {
    1876           0 :                                                         break;
    1877             :                                                 }
    1878             :                                         } else {
    1879           1 :                                                 list = estrdup((*entry)->name);
    1880             :                                         }
    1881           1 :                                         entry++;
    1882             :                                 }
    1883             :                         }
    1884           1 :                         if (!list) {
    1885           0 :                                 RETURN_FALSE;
    1886             :                         }
    1887           2 :                         RETVAL_STRING(list);
    1888           1 :                         efree(list);
    1889           1 :                         retname = 0;
    1890           1 :                         break;
    1891             :                 default:
    1892           0 :                         result = MBSTRG(http_input_identify);
    1893             :                         break;
    1894             :                 }
    1895             :         }
    1896             : 
    1897           2 :         if (retname) {
    1898           1 :                 if (result) {
    1899           2 :                         RETVAL_STRING(result->name);
    1900             :                 } else {
    1901           0 :                         RETVAL_FALSE;
    1902             :                 }
    1903             :         }
    1904             : }
    1905             : /* }}} */
    1906             : 
    1907             : /* {{{ proto string mb_http_output([string encoding])
    1908             :    Sets the current output_encoding or returns the current output_encoding as a string */
    1909          32 : PHP_FUNCTION(mb_http_output)
    1910             : {
    1911          32 :         const char *name = NULL;
    1912             :         size_t name_len;
    1913             :         const mbfl_encoding *encoding;
    1914             : 
    1915          32 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &name, &name_len) == FAILURE) {
    1916           2 :                 return;
    1917             :         }
    1918             : 
    1919          30 :         if (name == NULL) {
    1920           9 :                 name = MBSTRG(current_http_output_encoding) ? MBSTRG(current_http_output_encoding)->name: NULL;
    1921           9 :                 if (name != NULL) {
    1922          18 :                         RETURN_STRING(name);
    1923             :                 } else {
    1924           0 :                         RETURN_FALSE;
    1925             :                 }
    1926             :         } else {
    1927          21 :                 encoding = mbfl_name2encoding(name);
    1928          21 :                 if (!encoding) {
    1929           1 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", name);
    1930           1 :                         RETURN_FALSE;
    1931             :                 } else {
    1932          20 :                         MBSTRG(current_http_output_encoding) = encoding;
    1933          20 :                         RETURN_TRUE;
    1934             :                 }
    1935             :         }
    1936             : }
    1937             : /* }}} */
    1938             : 
    1939             : /* {{{ proto bool|array mb_detect_order([mixed encoding-list])
    1940             :    Sets the current detect_order or Return the current detect_order as a array */
    1941          12 : PHP_FUNCTION(mb_detect_order)
    1942             : {
    1943          12 :         zval *arg1 = NULL;
    1944             : 
    1945          12 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|z", &arg1) == FAILURE) {
    1946           0 :                 return;
    1947             :         }
    1948             : 
    1949          12 :         if (!arg1) {
    1950             :                 size_t i;
    1951           5 :                 size_t n = MBSTRG(current_detect_order_list_size);
    1952           5 :                 const mbfl_encoding **entry = MBSTRG(current_detect_order_list);
    1953           5 :                 array_init(return_value);
    1954          26 :                 for (i = 0; i < n; i++) {
    1955          21 :                         add_next_index_string(return_value, (*entry)->name);
    1956          21 :                         entry++;
    1957             :                 }
    1958             :         } else {
    1959           7 :                 const mbfl_encoding **list = NULL;
    1960           7 :                 size_t size = 0;
    1961          14 :                 switch (Z_TYPE_P(arg1)) {
    1962             :                         case IS_ARRAY:
    1963           2 :                                 if (FAILURE == php_mb_parse_encoding_array(arg1, &list, &size, 0)) {
    1964           1 :                                         if (list) {
    1965           1 :                                                 efree(list);
    1966             :                                         }
    1967           1 :                                         RETURN_FALSE;
    1968             :                                 }
    1969           1 :                                 break;
    1970             :                         default:
    1971          10 :                                 convert_to_string_ex(arg1);
    1972           5 :                                 if (FAILURE == php_mb_parse_encoding_list(Z_STRVAL_P(arg1), Z_STRLEN_P(arg1), &list, &size, 0)) {
    1973           0 :                                         if (list) {
    1974           0 :                                                 efree(list);
    1975             :                                         }
    1976           0 :                                         RETURN_FALSE;
    1977             :                                 }
    1978             :                                 break;
    1979             :                 }
    1980             : 
    1981           6 :                 if (list == NULL) {
    1982           1 :                         RETURN_FALSE;
    1983             :                 }
    1984             : 
    1985           5 :                 if (MBSTRG(current_detect_order_list)) {
    1986           5 :                         efree(MBSTRG(current_detect_order_list));
    1987             :                 }
    1988           5 :                 MBSTRG(current_detect_order_list) = list;
    1989           5 :                 MBSTRG(current_detect_order_list_size) = size;
    1990           5 :                 RETURN_TRUE;
    1991             :         }
    1992             : }
    1993             : /* }}} */
    1994             : 
    1995             : /* {{{ proto mixed mb_substitute_character([mixed substchar])
    1996             :    Sets the current substitute_character or returns the current substitute_character */
    1997          58 : PHP_FUNCTION(mb_substitute_character)
    1998             : {
    1999          58 :         zval *arg1 = NULL;
    2000             : 
    2001          58 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|z", &arg1) == FAILURE) {
    2002           1 :                 return;
    2003             :         }
    2004             : 
    2005          57 :         if (!arg1) {
    2006           8 :                 if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE) {
    2007           4 :                         RETURN_STRING("none");
    2008           6 :                 } else if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_LONG) {
    2009           2 :                         RETURN_STRING("long");
    2010           5 :                 } else if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_ENTITY) {
    2011           2 :                         RETURN_STRING("entity");
    2012             :                 } else {
    2013           4 :                         RETURN_LONG(MBSTRG(current_filter_illegal_substchar));
    2014             :                 }
    2015             :         } else {
    2016          49 :                 RETVAL_TRUE;
    2017             : 
    2018          98 :                 switch (Z_TYPE_P(arg1)) {
    2019             :                         case IS_STRING:
    2020          13 :                                 if (strncasecmp("none", Z_STRVAL_P(arg1), Z_STRLEN_P(arg1)) == 0) {
    2021           5 :                                         MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE;
    2022           8 :                                 } else if (strncasecmp("long", Z_STRVAL_P(arg1), Z_STRLEN_P(arg1)) == 0) {
    2023           1 :                                         MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_LONG;
    2024           7 :                                 } else if (strncasecmp("entity", Z_STRVAL_P(arg1), Z_STRLEN_P(arg1)) == 0) {
    2025           1 :                                         MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_ENTITY;
    2026             :                                 } else {
    2027          12 :                                         convert_to_long_ex(arg1);
    2028             : 
    2029           6 :                                         if (Z_LVAL_P(arg1) < 0xffff && Z_LVAL_P(arg1) > 0x0) {
    2030           0 :                                                 MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR;
    2031           0 :                                                 MBSTRG(current_filter_illegal_substchar) = Z_LVAL_P(arg1);
    2032             :                                         } else {
    2033           6 :                                                 php_error_docref(NULL, E_WARNING, "Unknown character.");
    2034           6 :                                                 RETURN_FALSE;
    2035             :                                         }
    2036             :                                 }
    2037           7 :                                 break;
    2038             :                         default:
    2039          72 :                                 convert_to_long_ex(arg1);
    2040          59 :                                 if (Z_LVAL_P(arg1) < 0xffff && Z_LVAL_P(arg1) > 0x0) {
    2041          23 :                                         MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR;
    2042          23 :                                         MBSTRG(current_filter_illegal_substchar) = Z_LVAL_P(arg1);
    2043             :                                 } else {
    2044          13 :                                         php_error_docref(NULL, E_WARNING, "Unknown character.");
    2045          13 :                                         RETURN_FALSE;
    2046             :                                 }
    2047             :                                 break;
    2048             :                 }
    2049             :         }
    2050             : }
    2051             : /* }}} */
    2052             : 
    2053             : /* {{{ proto string mb_preferred_mime_name(string encoding)
    2054             :    Return the preferred MIME name (charset) as a string */
    2055          10 : PHP_FUNCTION(mb_preferred_mime_name)
    2056             : {
    2057             :         enum mbfl_no_encoding no_encoding;
    2058          10 :         char *name = NULL;
    2059             :         size_t name_len;
    2060             : 
    2061          10 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
    2062           0 :                 return;
    2063             :         } else {
    2064          10 :                 no_encoding = mbfl_name2no_encoding(name);
    2065          10 :                 if (no_encoding == mbfl_no_encoding_invalid) {
    2066           1 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", name);
    2067           1 :                         RETVAL_FALSE;
    2068             :                 } else {
    2069           9 :                         const char *preferred_name = mbfl_no2preferred_mime_name(no_encoding);
    2070           9 :                         if (preferred_name == NULL || *preferred_name == '\0') {
    2071           0 :                                 php_error_docref(NULL, E_WARNING, "No MIME preferred name corresponding to \"%s\"", name);
    2072           0 :                                 RETVAL_FALSE;
    2073             :                         } else {
    2074          18 :                                 RETVAL_STRING((char *)preferred_name);
    2075             :                         }
    2076             :                 }
    2077             :         }
    2078             : }
    2079             : /* }}} */
    2080             : 
    2081             : #define IS_SJIS1(c) ((((c)>=0x81 && (c)<=0x9f) || ((c)>=0xe0 && (c)<=0xf5)) ? 1 : 0)
    2082             : #define IS_SJIS2(c) ((((c)>=0x40 && (c)<=0x7e) || ((c)>=0x80 && (c)<=0xfc)) ? 1 : 0)
    2083             : 
    2084             : /* {{{ proto bool mb_parse_str(string encoded_string [, array result])
    2085             :    Parses GET/POST/COOKIE data and sets global variables */
    2086          18 : PHP_FUNCTION(mb_parse_str)
    2087             : {
    2088          18 :         zval *track_vars_array = NULL;
    2089          18 :         char *encstr = NULL;
    2090             :         size_t encstr_len;
    2091             :         php_mb_encoding_handler_info_t info;
    2092             :         const mbfl_encoding *detected;
    2093             : 
    2094          18 :         track_vars_array = NULL;
    2095          18 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|z/", &encstr, &encstr_len, &track_vars_array) == FAILURE) {
    2096           0 :                 return;
    2097             :         }
    2098             : 
    2099          18 :         if (track_vars_array != NULL) {
    2100             :                 /* Clear out the array */
    2101           9 :                 zval_dtor(track_vars_array);
    2102           9 :                 array_init(track_vars_array);
    2103             :         }
    2104             : 
    2105          18 :         encstr = estrndup(encstr, encstr_len);
    2106             : 
    2107          18 :         info.data_type              = PARSE_STRING;
    2108          18 :         info.separator              = PG(arg_separator).input;
    2109          18 :         info.report_errors          = 1;
    2110          18 :         info.to_encoding            = MBSTRG(current_internal_encoding);
    2111          18 :         info.to_language            = MBSTRG(language);
    2112          18 :         info.from_encodings         = MBSTRG(http_input_list);
    2113          18 :         info.num_from_encodings     = MBSTRG(http_input_list_size);
    2114          18 :         info.from_language          = MBSTRG(language);
    2115             : 
    2116          18 :         if (track_vars_array != NULL) {
    2117           9 :                 detected = _php_mb_encoding_handler_ex(&info, track_vars_array, encstr);
    2118             :         } else {
    2119             :                 zval tmp;
    2120             :                 zend_array *symbol_table;
    2121           9 :                 if (zend_forbid_dynamic_call("mb_parse_str() with a single argument") == FAILURE) {
    2122           0 :                         efree(encstr);
    2123           0 :                         return;
    2124             :                 }
    2125             : 
    2126           9 :                 symbol_table = zend_rebuild_symbol_table();
    2127           9 :                 ZVAL_ARR(&tmp, symbol_table);
    2128           9 :                 detected = _php_mb_encoding_handler_ex(&info, &tmp, encstr);
    2129             :         }
    2130             : 
    2131          18 :         MBSTRG(http_input_identify) = detected;
    2132             : 
    2133          18 :         RETVAL_BOOL(detected);
    2134             : 
    2135          18 :         if (encstr != NULL) efree(encstr);
    2136             : }
    2137             : /* }}} */
    2138             : 
    2139             : /* {{{ proto string mb_output_handler(string contents, int status)
    2140             :    Returns string in output buffer converted to the http_output encoding */
    2141          19 : PHP_FUNCTION(mb_output_handler)
    2142             : {
    2143             :         char *arg_string;
    2144             :         size_t arg_string_len;
    2145             :         zend_long arg_status;
    2146             :         mbfl_string string, result;
    2147             :         const char *charset;
    2148             :         char *p;
    2149             :         const mbfl_encoding *encoding;
    2150             :         int last_feed, len;
    2151          19 :         unsigned char send_text_mimetype = 0;
    2152          19 :         char *s, *mimetype = NULL;
    2153             : 
    2154          19 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl", &arg_string, &arg_string_len, &arg_status) == FAILURE) {
    2155           0 :                 return;
    2156             :         }
    2157             : 
    2158          19 :         encoding = MBSTRG(current_http_output_encoding);
    2159             : 
    2160             :         /* start phase only */
    2161          19 :         if ((arg_status & PHP_OUTPUT_HANDLER_START) != 0) {
    2162             :                 /* delete the converter just in case. */
    2163          19 :                 if (MBSTRG(outconv)) {
    2164           0 :                         MBSTRG(illegalchars) += mbfl_buffer_illegalchars(MBSTRG(outconv));
    2165           0 :                         mbfl_buffer_converter_delete(MBSTRG(outconv));
    2166           0 :                         MBSTRG(outconv) = NULL;
    2167             :                 }
    2168          19 :                 if (encoding == &mbfl_encoding_pass) {
    2169           0 :                         RETURN_STRINGL(arg_string, arg_string_len);
    2170             :                 }
    2171             : 
    2172             :                 /* analyze mime type */
    2173          39 :                 if (SG(sapi_headers).mimetype &&
    2174             :                         _php_mb_match_regex(
    2175             :                                 MBSTRG(http_output_conv_mimetypes),
    2176          12 :                                 SG(sapi_headers).mimetype,
    2177          24 :                                 strlen(SG(sapi_headers).mimetype))) {
    2178           8 :                         if ((s = strchr(SG(sapi_headers).mimetype,';')) == NULL){
    2179           2 :                                 mimetype = estrdup(SG(sapi_headers).mimetype);
    2180             :                         } else {
    2181           6 :                                 mimetype = estrndup(SG(sapi_headers).mimetype,s-SG(sapi_headers).mimetype);
    2182             :                         }
    2183           8 :                         send_text_mimetype = 1;
    2184          11 :                 } else if (SG(sapi_headers).send_default_content_type) {
    2185           7 :                         mimetype = SG(default_mimetype) ? SG(default_mimetype) : SAPI_DEFAULT_MIMETYPE;
    2186             :                 }
    2187             : 
    2188             :                 /* if content-type is not yet set, set it and activate the converter */
    2189          19 :                 if (SG(sapi_headers).send_default_content_type || send_text_mimetype) {
    2190          15 :                         charset = encoding->mime_name;
    2191          15 :                         if (charset) {
    2192          15 :                                 len = spprintf( &p, 0, "Content-Type: %s; charset=%s",  mimetype, charset );
    2193          15 :                                 if (sapi_add_header(p, len, 0) != FAILURE) {
    2194          15 :                                         SG(sapi_headers).send_default_content_type = 0;
    2195             :                                 }
    2196             :                         }
    2197             :                         /* activate the converter */
    2198          15 :                         MBSTRG(outconv) = mbfl_buffer_converter_new2(MBSTRG(current_internal_encoding), encoding, 0);
    2199          15 :                         if (send_text_mimetype){
    2200           8 :                                 efree(mimetype);
    2201             :                         }
    2202             :                 }
    2203             :         }
    2204             : 
    2205             :         /* just return if the converter is not activated. */
    2206          19 :         if (MBSTRG(outconv) == NULL) {
    2207           8 :                 RETURN_STRINGL(arg_string, arg_string_len);
    2208             :         }
    2209             : 
    2210             :         /* flag */
    2211          15 :         last_feed = ((arg_status & PHP_OUTPUT_HANDLER_END) != 0);
    2212             :         /* mode */
    2213          15 :         mbfl_buffer_converter_illegal_mode(MBSTRG(outconv), MBSTRG(current_filter_illegal_mode));
    2214          15 :         mbfl_buffer_converter_illegal_substchar(MBSTRG(outconv), MBSTRG(current_filter_illegal_substchar));
    2215             : 
    2216             :         /* feed the string */
    2217          15 :         mbfl_string_init(&string);
    2218             :         /* these are not needed. convd has encoding info.
    2219             :         string.no_language = MBSTRG(language);
    2220             :         string.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2221             :         */
    2222          15 :         string.val = (unsigned char *)arg_string;
    2223          15 :         string.len = arg_string_len;
    2224          15 :         mbfl_buffer_converter_feed(MBSTRG(outconv), &string);
    2225          15 :         if (last_feed) {
    2226          15 :                 mbfl_buffer_converter_flush(MBSTRG(outconv));
    2227             :         }
    2228             :         /* get the converter output, and return it */
    2229          15 :         mbfl_buffer_converter_result(MBSTRG(outconv), &result);
    2230             :         // TODO: avoid reallocation ???
    2231          30 :         RETVAL_STRINGL((char *)result.val, result.len);         /* the string is already strdup()'ed */
    2232          15 :         efree(result.val);
    2233             : 
    2234             :         /* delete the converter if it is the last feed. */
    2235          15 :         if (last_feed) {
    2236          15 :                 MBSTRG(illegalchars) += mbfl_buffer_illegalchars(MBSTRG(outconv));
    2237          15 :                 mbfl_buffer_converter_delete(MBSTRG(outconv));
    2238          15 :                 MBSTRG(outconv) = NULL;
    2239             :         }
    2240             : }
    2241             : /* }}} */
    2242             : 
    2243             : /* {{{ proto int mb_strlen(string str [, string encoding])
    2244             :    Get character numbers of a string */
    2245         233 : PHP_FUNCTION(mb_strlen)
    2246             : {
    2247             :         int n;
    2248             :         mbfl_string string;
    2249         233 :         char *enc_name = NULL;
    2250             :         size_t enc_name_len, string_len;
    2251             : 
    2252         233 :         mbfl_string_init(&string);
    2253             : 
    2254         233 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s", (char **)&string.val, &string_len, &enc_name, &enc_name_len) == FAILURE) {
    2255           4 :                 return;
    2256             :         }
    2257             : 
    2258         229 :         if (ZEND_SIZE_T_UINT_OVFL(string_len)) {
    2259           0 :                         php_error_docref(NULL, E_WARNING, "String overflows the max allowed length of %u", UINT_MAX);
    2260           0 :                         return;
    2261             :         }
    2262             : 
    2263         229 :         string.len = (uint32_t)string_len;
    2264             : 
    2265         229 :         string.no_language = MBSTRG(language);
    2266         229 :         if (enc_name == NULL) {
    2267           7 :                 string.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2268             :         } else {
    2269         222 :                 string.no_encoding = mbfl_name2no_encoding(enc_name);
    2270         222 :                 if (string.no_encoding == mbfl_no_encoding_invalid) {
    2271          21 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", enc_name);
    2272          21 :                         RETURN_FALSE;
    2273             :                 }
    2274             :         }
    2275             : 
    2276         208 :         n = mbfl_strlen(&string);
    2277         208 :         if (n >= 0) {
    2278         208 :                 RETVAL_LONG(n);
    2279             :         } else {
    2280           0 :                 RETVAL_FALSE;
    2281             :         }
    2282             : }
    2283             : /* }}} */
    2284             : 
    2285             : /* {{{ proto int mb_strpos(string haystack, string needle [, int offset [, string encoding]])
    2286             :    Find position of first occurrence of a string within another */
    2287         199 : PHP_FUNCTION(mb_strpos)
    2288             : {
    2289         199 :         int n, reverse = 0;
    2290         199 :         zend_long offset = 0, slen;
    2291             :         mbfl_string haystack, needle;
    2292         199 :         char *enc_name = NULL;
    2293             :         size_t enc_name_len, haystack_len, needle_len;
    2294             : 
    2295         199 :         mbfl_string_init(&haystack);
    2296         199 :         mbfl_string_init(&needle);
    2297         199 :         haystack.no_language = MBSTRG(language);
    2298         199 :         haystack.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2299         199 :         needle.no_language = MBSTRG(language);
    2300         199 :         needle.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2301             : 
    2302         199 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|ls", (char **)&haystack.val, &haystack_len, (char **)&needle.val, &needle_len, &offset, &enc_name, &enc_name_len) == FAILURE) {
    2303          16 :                 return;
    2304             :         }
    2305             : 
    2306         183 :         if (ZEND_SIZE_T_UINT_OVFL(haystack_len)) {
    2307           0 :                         php_error_docref(NULL, E_WARNING, "Haystack length overflows the max allowed length of %u", UINT_MAX);
    2308           0 :                         return;
    2309         183 :         } else if (ZEND_SIZE_T_UINT_OVFL(needle_len)) {
    2310           0 :                         php_error_docref(NULL, E_WARNING, "Needle length overflows the max allowed length of %u", UINT_MAX);
    2311           0 :                         return;
    2312             :         }
    2313             : 
    2314         183 :         haystack.len = (uint32_t)haystack_len;
    2315         183 :         needle.len = (uint32_t)needle_len;
    2316             : 
    2317         183 :         if (enc_name != NULL) {
    2318         139 :                 haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(enc_name);
    2319         139 :                 if (haystack.no_encoding == mbfl_no_encoding_invalid) {
    2320          20 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", enc_name);
    2321          20 :                         RETURN_FALSE;
    2322             :                 }
    2323             :         }
    2324             : 
    2325         163 :         slen = mbfl_strlen(&haystack);
    2326         163 :         if (offset < 0) {
    2327          28 :                 offset += slen;
    2328             :         }
    2329         163 :         if (offset < 0 || offset > slen) {
    2330          32 :                 php_error_docref(NULL, E_WARNING, "Offset not contained in string");
    2331          32 :                 RETURN_FALSE;
    2332             :         }
    2333         131 :         if (needle.len == 0) {
    2334           8 :                 php_error_docref(NULL, E_WARNING, "Empty delimiter");
    2335           8 :                 RETURN_FALSE;
    2336             :         }
    2337             : 
    2338         123 :         n = mbfl_strpos(&haystack, &needle, offset, reverse);
    2339         123 :         if (n >= 0) {
    2340          65 :                 RETVAL_LONG(n);
    2341             :         } else {
    2342          58 :                 switch (-n) {
    2343             :                 case 1:
    2344          58 :                         break;
    2345             :                 case 2:
    2346           0 :                         php_error_docref(NULL, E_WARNING, "Needle has not positive length");
    2347           0 :                         break;
    2348             :                 case 4:
    2349           0 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding or conversion error");
    2350           0 :                         break;
    2351             :                 case 8:
    2352           0 :                         php_error_docref(NULL, E_NOTICE, "Argument is empty");
    2353           0 :                         break;
    2354             :                 default:
    2355           0 :                         php_error_docref(NULL, E_WARNING, "Unknown error in mb_strpos");
    2356             :                         break;
    2357             :                 }
    2358          58 :                 RETVAL_FALSE;
    2359             :         }
    2360             : }
    2361             : /* }}} */
    2362             : 
    2363             : /* {{{ proto int mb_strrpos(string haystack, string needle [, int offset [, string encoding]])
    2364             :    Find position of last occurrence of a string within another */
    2365         122 : PHP_FUNCTION(mb_strrpos)
    2366             : {
    2367             :         int n;
    2368             :         mbfl_string haystack, needle;
    2369         122 :         char *enc_name = NULL;
    2370             :         size_t enc_name_len, haystack_len, needle_len;
    2371         122 :         zval *zoffset = NULL;
    2372         122 :         long offset = 0, str_flg;
    2373         122 :         char *enc_name2 = NULL;
    2374             :         int enc_name_len2;
    2375             : 
    2376         122 :         mbfl_string_init(&haystack);
    2377         122 :         mbfl_string_init(&needle);
    2378         122 :         haystack.no_language = MBSTRG(language);
    2379         122 :         haystack.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2380         122 :         needle.no_language = MBSTRG(language);
    2381         122 :         needle.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2382             : 
    2383         122 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|zs", (char **)&haystack.val, &haystack_len, (char **)&needle.val, &needle_len, &zoffset, &enc_name, &enc_name_len) == FAILURE) {
    2384           5 :                 return;
    2385             :         }
    2386             : 
    2387         117 :         if (ZEND_SIZE_T_UINT_OVFL(haystack_len)) {
    2388           0 :                         php_error_docref(NULL, E_WARNING, "Haystack length overflows the max allowed length of %u", UINT_MAX);
    2389           0 :                         return;
    2390         117 :         } else if (ZEND_SIZE_T_UINT_OVFL(needle_len)) {
    2391           0 :                         php_error_docref(NULL, E_WARNING, "Needle length overflows the max allowed length of %u", UINT_MAX);
    2392           0 :                         return;
    2393             :         }
    2394             : 
    2395         117 :         haystack.len = (uint32_t)haystack_len;
    2396         117 :         needle.len = (uint32_t)needle_len;
    2397             : 
    2398         117 :         if (zoffset) {
    2399         228 :                 if (Z_TYPE_P(zoffset) == IS_STRING) {
    2400           6 :                         enc_name2     = Z_STRVAL_P(zoffset);
    2401           6 :                         enc_name_len2 = Z_STRLEN_P(zoffset);
    2402           6 :                         str_flg       = 1;
    2403             : 
    2404           6 :                         if (enc_name2 != NULL) {
    2405           6 :                                 switch (*enc_name2) {
    2406             :                                         case '0':
    2407             :                                         case '1':
    2408             :                                         case '2':
    2409             :                                         case '3':
    2410             :                                         case '4':
    2411             :                                         case '5':
    2412             :                                         case '6':
    2413             :                                         case '7':
    2414             :                                         case '8':
    2415             :                                         case '9':
    2416             :                                         case ' ':
    2417             :                                         case '-':
    2418             :                                         case '.':
    2419           0 :                                                 break;
    2420             :                                         default :
    2421           6 :                                                 str_flg = 0;
    2422             :                                                 break;
    2423             :                                 }
    2424             :                         }
    2425             : 
    2426           6 :                         if (str_flg) {
    2427           0 :                                 convert_to_long_ex(zoffset);
    2428           0 :                                 offset   = Z_LVAL_P(zoffset);
    2429             :                         } else {
    2430           6 :                                 enc_name     = enc_name2;
    2431           6 :                                 enc_name_len = enc_name_len2;
    2432             :                         }
    2433             :                 } else {
    2434         216 :                         convert_to_long_ex(zoffset);
    2435         108 :                         offset = Z_LVAL_P(zoffset);
    2436             :                 }
    2437             :         }
    2438             : 
    2439         117 :         if (enc_name != NULL) {
    2440         100 :                 haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(enc_name);
    2441         100 :                 if (haystack.no_encoding == mbfl_no_encoding_invalid) {
    2442          20 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", enc_name);
    2443          20 :                         RETURN_FALSE;
    2444             :                 }
    2445             :         }
    2446             : 
    2447          97 :         if (haystack.len <= 0) {
    2448           8 :                 RETURN_FALSE;
    2449             :         }
    2450          89 :         if (needle.len <= 0) {
    2451           8 :                 RETURN_FALSE;
    2452             :         }
    2453             : 
    2454             :         {
    2455          81 :                 int haystack_char_len = mbfl_strlen(&haystack);
    2456          95 :                 if ((offset > 0 && offset > haystack_char_len) ||
    2457          14 :                         (offset < 0 && -offset > haystack_char_len)) {
    2458           9 :                         php_error_docref(NULL, E_WARNING, "Offset is greater than the length of haystack string");
    2459           9 :                         RETURN_FALSE;
    2460             :                 }
    2461             :         }
    2462             : 
    2463          72 :         n = mbfl_strpos(&haystack, &needle, offset, 1);
    2464          72 :         if (n >= 0) {
    2465          42 :                 RETVAL_LONG(n);
    2466             :         } else {
    2467          30 :                 RETVAL_FALSE;
    2468             :         }
    2469             : }
    2470             : /* }}} */
    2471             : 
    2472             : /* {{{ proto int mb_stripos(string haystack, string needle [, int offset [, string encoding]])
    2473             :    Finds position of first occurrence of a string within another, case insensitive */
    2474         277 : PHP_FUNCTION(mb_stripos)
    2475             : {
    2476         277 :         int n = -1;
    2477         277 :         zend_long offset = 0;
    2478             :         mbfl_string haystack, needle;
    2479         277 :         const char *from_encoding = MBSTRG(current_internal_encoding)->mime_name;
    2480             :         size_t from_encoding_len, haystack_len, needle_len;
    2481             : 
    2482         277 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|ls", (char **)&haystack.val, &haystack_len, (char **)&needle.val, &needle_len, &offset, &from_encoding, &from_encoding_len) == FAILURE) {
    2483          16 :                 return;
    2484             :         }
    2485             : 
    2486         261 :         if (ZEND_SIZE_T_UINT_OVFL(haystack_len)) {
    2487           0 :                         php_error_docref(NULL, E_WARNING, "Haystack length overflows the max allowed length of %u", UINT_MAX);
    2488           0 :                         return;
    2489         261 :         } else if (ZEND_SIZE_T_UINT_OVFL(needle_len)) {
    2490           0 :                         php_error_docref(NULL, E_WARNING, "Needle length overflows the max allowed length of %u", UINT_MAX);
    2491           0 :                         return;
    2492             :         }
    2493             : 
    2494         261 :         haystack.len = (uint32_t)haystack_len;
    2495         261 :         needle.len = (uint32_t)needle_len;
    2496             : 
    2497         261 :         if (needle.len == 0) {
    2498           8 :                 php_error_docref(NULL, E_WARNING, "Empty delimiter");
    2499           8 :                 RETURN_FALSE;
    2500             :         }
    2501         253 :         n = php_mb_stripos(0, (char *)haystack.val, haystack.len, (char *)needle.val, needle.len, offset, from_encoding);
    2502             : 
    2503         253 :         if (n >= 0) {
    2504         129 :                 RETVAL_LONG(n);
    2505             :         } else {
    2506         124 :                 RETVAL_FALSE;
    2507             :         }
    2508             : }
    2509             : /* }}} */
    2510             : 
    2511             : /* {{{ proto int mb_strripos(string haystack, string needle [, int offset [, string encoding]])
    2512             :    Finds position of last occurrence of a string within another, case insensitive */
    2513         224 : PHP_FUNCTION(mb_strripos)
    2514             : {
    2515         224 :         int n = -1;
    2516         224 :         zend_long offset = 0;
    2517             :         mbfl_string haystack, needle;
    2518         224 :         const char *from_encoding = MBSTRG(current_internal_encoding)->mime_name;
    2519             :         size_t from_encoding_len, haystack_len, needle_len;
    2520             : 
    2521         224 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|ls", (char **)&haystack.val, &haystack_len, (char **)&needle.val, &needle_len, &offset, &from_encoding, &from_encoding_len) == FAILURE) {
    2522          12 :                 return;
    2523             :         }
    2524             : 
    2525         212 :         if (ZEND_SIZE_T_UINT_OVFL(haystack_len)) {
    2526           0 :                         php_error_docref(NULL, E_WARNING, "Haystack length overflows the max allowed length of %u", UINT_MAX);
    2527           0 :                         return;
    2528         212 :         } else if (ZEND_SIZE_T_UINT_OVFL(needle_len)) {
    2529           0 :                         php_error_docref(NULL, E_WARNING, "Needle length overflows the max allowed length of %u", UINT_MAX);
    2530           0 :                         return;
    2531             :         }
    2532             : 
    2533         212 :         haystack.len = (uint32_t)haystack_len;
    2534         212 :         needle.len = (uint32_t)needle_len;
    2535             : 
    2536         212 :         n = php_mb_stripos(1, (char *)haystack.val, haystack.len, (char *)needle.val, needle.len, offset, from_encoding);
    2537             : 
    2538         212 :         if (n >= 0) {
    2539          83 :                 RETVAL_LONG(n);
    2540             :         } else {
    2541         129 :                 RETVAL_FALSE;
    2542             :         }
    2543             : }
    2544             : /* }}} */
    2545             : 
    2546             : /* {{{ proto string mb_strstr(string haystack, string needle[, bool part[, string encoding]])
    2547             :    Finds first occurrence of a string within another */
    2548         138 : PHP_FUNCTION(mb_strstr)
    2549             : {
    2550             :         int n, len, mblen;
    2551         138 :         mbfl_string haystack, needle, result, *ret = NULL;
    2552         138 :         char *enc_name = NULL;
    2553             :         size_t enc_name_len, haystack_len, needle_len;
    2554         138 :         zend_bool part = 0;
    2555             : 
    2556         138 :         mbfl_string_init(&haystack);
    2557         138 :         mbfl_string_init(&needle);
    2558         138 :         haystack.no_language = MBSTRG(language);
    2559         138 :         haystack.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2560         138 :         needle.no_language = MBSTRG(language);
    2561         138 :         needle.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2562             : 
    2563         138 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|bs", (char **)&haystack.val, &haystack_len, (char **)&needle.val, &needle_len, &part, &enc_name, &enc_name_len) == FAILURE) {
    2564          27 :                 return;
    2565             :         }
    2566             : 
    2567         111 :         if (ZEND_SIZE_T_UINT_OVFL(haystack_len)) {
    2568           0 :                         php_error_docref(NULL, E_WARNING, "Haystack length overflows the max allowed length of %u", UINT_MAX);
    2569           0 :                         return;
    2570         111 :         } else if (ZEND_SIZE_T_UINT_OVFL(needle_len)) {
    2571           0 :                         php_error_docref(NULL, E_WARNING, "Needle length overflows the max allowed length of %u", UINT_MAX);
    2572           0 :                         return;
    2573             :         }
    2574             : 
    2575         111 :         haystack.len = (uint32_t)haystack_len;
    2576         111 :         needle.len = (uint32_t)needle_len;
    2577             : 
    2578         111 :         if (enc_name != NULL) {
    2579          89 :                 haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(enc_name);
    2580          89 :                 if (haystack.no_encoding == mbfl_no_encoding_invalid) {
    2581          21 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", enc_name);
    2582          21 :                         RETURN_FALSE;
    2583             :                 }
    2584             :         }
    2585             : 
    2586          90 :         if (needle.len <= 0) {
    2587           8 :                 php_error_docref(NULL, E_WARNING, "Empty delimiter");
    2588           8 :                 RETURN_FALSE;
    2589             :         }
    2590          82 :         n = mbfl_strpos(&haystack, &needle, 0, 0);
    2591          82 :         if (n >= 0) {
    2592          44 :                 mblen = mbfl_strlen(&haystack);
    2593          44 :                 if (part) {
    2594          21 :                         ret = mbfl_substr(&haystack, &result, 0, n);
    2595          21 :                         if (ret != NULL) {
    2596             :                                 // TODO: avoid reallocation ???
    2597          42 :                                 RETVAL_STRINGL((char *)ret->val, ret->len);
    2598          21 :                                 efree(ret->val);
    2599             :                         } else {
    2600           0 :                                 RETVAL_FALSE;
    2601             :                         }
    2602             :                 } else {
    2603          23 :                         len = (mblen - n);
    2604          23 :                         ret = mbfl_substr(&haystack, &result, n, len);
    2605          23 :                         if (ret != NULL) {
    2606             :                                 // TODO: avoid reallocation ???
    2607          46 :                                 RETVAL_STRINGL((char *)ret->val, ret->len);
    2608          23 :                                 efree(ret->val);
    2609             :                         } else {
    2610           0 :                                 RETVAL_FALSE;
    2611             :                         }
    2612             :                 }
    2613             :         } else {
    2614          38 :                 RETVAL_FALSE;
    2615             :         }
    2616             : }
    2617             : /* }}} */
    2618             : 
    2619             : /* {{{ proto string mb_strrchr(string haystack, string needle[, bool part[, string encoding]])
    2620             :    Finds the last occurrence of a character in a string within another */
    2621         130 : PHP_FUNCTION(mb_strrchr)
    2622             : {
    2623             :         int n, len, mblen;
    2624         130 :         mbfl_string haystack, needle, result, *ret = NULL;
    2625         130 :         char *enc_name = NULL;
    2626             :         size_t enc_name_len, haystack_len, needle_len;
    2627         130 :         zend_bool part = 0;
    2628             : 
    2629         130 :         mbfl_string_init(&haystack);
    2630         130 :         mbfl_string_init(&needle);
    2631         130 :         haystack.no_language = MBSTRG(language);
    2632         130 :         haystack.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2633         130 :         needle.no_language = MBSTRG(language);
    2634         130 :         needle.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2635             : 
    2636         130 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|bs", (char **)&haystack.val, &haystack_len, (char **)&needle.val, &needle_len, &part, &enc_name, &enc_name_len) == FAILURE) {
    2637          27 :                 return;
    2638             :         }
    2639             : 
    2640         103 :         if (ZEND_SIZE_T_UINT_OVFL(haystack_len)) {
    2641           0 :                         php_error_docref(NULL, E_WARNING, "Haystack length overflows the max allowed length of %u", UINT_MAX);
    2642           0 :                         return;
    2643         103 :         } else if (ZEND_SIZE_T_UINT_OVFL(needle_len)) {
    2644           0 :                         php_error_docref(NULL, E_WARNING, "Needle length overflows the max allowed length of %u", UINT_MAX);
    2645           0 :                         return;
    2646             :         }
    2647             : 
    2648         103 :         haystack.len = (uint32_t)haystack_len;
    2649         103 :         needle.len = (uint32_t)needle_len;
    2650             : 
    2651         103 :         if (enc_name != NULL) {
    2652          87 :                 haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(enc_name);
    2653          87 :                 if (haystack.no_encoding == mbfl_no_encoding_invalid) {
    2654          21 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", enc_name);
    2655          21 :                         RETURN_FALSE;
    2656             :                 }
    2657             :         }
    2658             : 
    2659          82 :         if (haystack.len <= 0) {
    2660           8 :                 RETURN_FALSE;
    2661             :         }
    2662          74 :         if (needle.len <= 0) {
    2663           8 :                 RETURN_FALSE;
    2664             :         }
    2665          66 :         n = mbfl_strpos(&haystack, &needle, 0, 1);
    2666          66 :         if (n >= 0) {
    2667          36 :                 mblen = mbfl_strlen(&haystack);
    2668          36 :                 if (part) {
    2669          18 :                         ret = mbfl_substr(&haystack, &result, 0, n);
    2670          18 :                         if (ret != NULL) {
    2671             :                                 // TODO: avoid reallocation ???
    2672          36 :                                 RETVAL_STRINGL((char *)ret->val, ret->len);
    2673          18 :                                 efree(ret->val);
    2674             :                         } else {
    2675           0 :                                 RETVAL_FALSE;
    2676             :                         }
    2677             :                 } else {
    2678          18 :                         len = (mblen - n);
    2679          18 :                         ret = mbfl_substr(&haystack, &result, n, len);
    2680          18 :                         if (ret != NULL) {
    2681             :                                 // TODO: avoid reallocation ???
    2682          36 :                                 RETVAL_STRINGL((char *)ret->val, ret->len);
    2683          18 :                                 efree(ret->val);
    2684             :                         } else {
    2685           0 :                                 RETVAL_FALSE;
    2686             :                         }
    2687             :                 }
    2688             :         } else {
    2689          30 :                 RETVAL_FALSE;
    2690             :         }
    2691             : }
    2692             : /* }}} */
    2693             : 
    2694             : /* {{{ proto string mb_stristr(string haystack, string needle[, bool part[, string encoding]])
    2695             :    Finds first occurrence of a string within another, case insensitive */
    2696         132 : PHP_FUNCTION(mb_stristr)
    2697             : {
    2698         132 :         zend_bool part = 0;
    2699             :         size_t from_encoding_len, len, mblen, haystack_len, needle_len;
    2700             :         int n;
    2701         132 :         mbfl_string haystack, needle, result, *ret = NULL;
    2702         132 :         const char *from_encoding = MBSTRG(current_internal_encoding)->mime_name;
    2703         132 :         mbfl_string_init(&haystack);
    2704         132 :         mbfl_string_init(&needle);
    2705         132 :         haystack.no_language = MBSTRG(language);
    2706         132 :         haystack.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2707         132 :         needle.no_language = MBSTRG(language);
    2708         132 :         needle.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2709             : 
    2710             : 
    2711         132 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|bs", (char **)&haystack.val, &haystack_len, (char **)&needle.val, &needle_len, &part, &from_encoding, &from_encoding_len) == FAILURE) {
    2712          27 :                 return;
    2713             :         }
    2714             : 
    2715         105 :         if (ZEND_SIZE_T_UINT_OVFL(haystack_len)) {
    2716           0 :                         php_error_docref(NULL, E_WARNING, "Haystack length overflows the max allowed length of %u", UINT_MAX);
    2717           0 :                         return;
    2718         105 :         } else if (ZEND_SIZE_T_UINT_OVFL(needle_len)) {
    2719           0 :                         php_error_docref(NULL, E_WARNING, "Needle length overflows the max allowed length of %u", UINT_MAX);
    2720           0 :                         return;
    2721             :         }
    2722             : 
    2723         105 :         haystack.len = (uint32_t)haystack_len;
    2724         105 :         needle.len = (uint32_t)needle_len;
    2725             : 
    2726         105 :         if (!needle.len) {
    2727           8 :                 php_error_docref(NULL, E_WARNING, "Empty delimiter");
    2728           8 :                 RETURN_FALSE;
    2729             :         }
    2730             : 
    2731          97 :         haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(from_encoding);
    2732          97 :         if (haystack.no_encoding == mbfl_no_encoding_invalid) {
    2733          21 :                 php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", from_encoding);
    2734          21 :                 RETURN_FALSE;
    2735             :         }
    2736             : 
    2737          76 :         n = php_mb_stripos(0, (char *)haystack.val, haystack.len, (char *)needle.val, needle.len, 0, from_encoding);
    2738             : 
    2739          76 :         if (n <0) {
    2740          34 :                 RETURN_FALSE;
    2741             :         }
    2742             : 
    2743          42 :         mblen = mbfl_strlen(&haystack);
    2744             : 
    2745          42 :         if (part) {
    2746          22 :                 ret = mbfl_substr(&haystack, &result, 0, n);
    2747          22 :                 if (ret != NULL) {
    2748             :                         // TODO: avoid reallocation ???
    2749          44 :                         RETVAL_STRINGL((char *)ret->val, ret->len);
    2750          22 :                         efree(ret->val);
    2751             :                 } else {
    2752           0 :                         RETVAL_FALSE;
    2753             :                 }
    2754             :         } else {
    2755          20 :                 len = (mblen - n);
    2756          20 :                 ret = mbfl_substr(&haystack, &result, n, len);
    2757          20 :                 if (ret != NULL) {
    2758             :                         // TODO: avoid reallocaton ???
    2759          40 :                         RETVAL_STRINGL((char *)ret->val, ret->len);
    2760          20 :                         efree(ret->val);
    2761             :                 } else {
    2762           0 :                         RETVAL_FALSE;
    2763             :                 }
    2764             :         }
    2765             : }
    2766             : /* }}} */
    2767             : 
    2768             : /* {{{ proto string mb_strrichr(string haystack, string needle[, bool part[, string encoding]])
    2769             :    Finds the last occurrence of a character in a string within another, case insensitive */
    2770         132 : PHP_FUNCTION(mb_strrichr)
    2771             : {
    2772         132 :         zend_bool part = 0;
    2773             :         int n, len, mblen;
    2774             :         size_t from_encoding_len, haystack_len, needle_len;
    2775         132 :         mbfl_string haystack, needle, result, *ret = NULL;
    2776         132 :         const char *from_encoding = MBSTRG(current_internal_encoding)->name;
    2777         132 :         mbfl_string_init(&haystack);
    2778         132 :         mbfl_string_init(&needle);
    2779         132 :         haystack.no_language = MBSTRG(language);
    2780         132 :         haystack.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2781         132 :         needle.no_language = MBSTRG(language);
    2782         132 :         needle.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2783             : 
    2784             : 
    2785         132 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|bs", (char **)&haystack.val, &haystack_len, (char **)&needle.val, &needle_len, &part, &from_encoding, &from_encoding_len) == FAILURE) {
    2786          27 :                 return;
    2787             :         }
    2788             : 
    2789         105 :         if (ZEND_SIZE_T_UINT_OVFL(haystack_len)) {
    2790           0 :                         php_error_docref(NULL, E_WARNING, "Haystack length overflows the max allowed length of %u", UINT_MAX);
    2791           0 :                         return;
    2792         105 :         } else if (ZEND_SIZE_T_UINT_OVFL(needle_len)) {
    2793           0 :                         php_error_docref(NULL, E_WARNING, "Needle length overflows the max allowed length of %u", UINT_MAX);
    2794           0 :                         return;
    2795             :         }
    2796             : 
    2797         105 :         haystack.len = (uint32_t)haystack_len;
    2798         105 :         needle.len = (uint32_t)needle_len;
    2799             : 
    2800         105 :         haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(from_encoding);
    2801         105 :         if (haystack.no_encoding == mbfl_no_encoding_invalid) {
    2802          21 :                 php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", from_encoding);
    2803          21 :                 RETURN_FALSE;
    2804             :         }
    2805             : 
    2806          84 :         n = php_mb_stripos(1, (char *)haystack.val, haystack.len, (char *)needle.val, needle.len, 0, from_encoding);
    2807             : 
    2808          84 :         if (n <0) {
    2809          42 :                 RETURN_FALSE;
    2810             :         }
    2811             : 
    2812          42 :         mblen = mbfl_strlen(&haystack);
    2813             : 
    2814          42 :         if (part) {
    2815          22 :                 ret = mbfl_substr(&haystack, &result, 0, n);
    2816          22 :                 if (ret != NULL) {
    2817             :                         // TODO: avoid reallocation ???
    2818          44 :                         RETVAL_STRINGL((char *)ret->val, ret->len);
    2819          22 :                         efree(ret->val);
    2820             :                 } else {
    2821           0 :                         RETVAL_FALSE;
    2822             :                 }
    2823             :         } else {
    2824          20 :                 len = (mblen - n);
    2825          20 :                 ret = mbfl_substr(&haystack, &result, n, len);
    2826          20 :                 if (ret != NULL) {
    2827             :                         // TODO: avoid reallocation ???
    2828          40 :                         RETVAL_STRINGL((char *)ret->val, ret->len);
    2829          20 :                         efree(ret->val);
    2830             :                 } else {
    2831           0 :                         RETVAL_FALSE;
    2832             :                 }
    2833             :         }
    2834             : }
    2835             : /* }}} */
    2836             : 
    2837             : /* {{{ proto int mb_substr_count(string haystack, string needle [, string encoding])
    2838             :    Count the number of substring occurrences */
    2839         100 : PHP_FUNCTION(mb_substr_count)
    2840             : {
    2841             :         int n;
    2842             :         mbfl_string haystack, needle;
    2843         100 :         char *enc_name = NULL;
    2844             :         size_t enc_name_len, haystack_len, needle_len;
    2845             : 
    2846         100 :         mbfl_string_init(&haystack);
    2847         100 :         mbfl_string_init(&needle);
    2848         100 :         haystack.no_language = MBSTRG(language);
    2849         100 :         haystack.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2850         100 :         needle.no_language = MBSTRG(language);
    2851         100 :         needle.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2852             : 
    2853         100 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|s", (char **)&haystack.val, &haystack_len, (char **)&needle.val, &needle_len, &enc_name, &enc_name_len) == FAILURE) {
    2854           5 :                 return;
    2855             :         }
    2856             : 
    2857          95 :         if (ZEND_SIZE_T_UINT_OVFL(haystack_len)) {
    2858           0 :                         php_error_docref(NULL, E_WARNING, "Haystack length overflows the max allowed length of %u", UINT_MAX);
    2859           0 :                         return;
    2860          95 :         } else if (ZEND_SIZE_T_UINT_OVFL(needle_len)) {
    2861           0 :                         php_error_docref(NULL, E_WARNING, "Needle length overflows the max allowed length of %u", UINT_MAX);
    2862           0 :                         return;
    2863             :         }
    2864             : 
    2865          95 :         haystack.len = (uint32_t)haystack_len;
    2866          95 :         needle.len = (uint32_t)needle_len;
    2867             : 
    2868          95 :         if (enc_name != NULL) {
    2869          27 :                 haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(enc_name);
    2870          27 :                 if (haystack.no_encoding == mbfl_no_encoding_invalid) {
    2871          20 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", enc_name);
    2872          20 :                         RETURN_FALSE;
    2873             :                 }
    2874             :         }
    2875             : 
    2876          75 :         if (needle.len <= 0) {
    2877          10 :                 php_error_docref(NULL, E_WARNING, "Empty substring");
    2878          10 :                 RETURN_FALSE;
    2879             :         }
    2880             : 
    2881          65 :         n = mbfl_substr_count(&haystack, &needle);
    2882          65 :         if (n >= 0) {
    2883          65 :                 RETVAL_LONG(n);
    2884             :         } else {
    2885           0 :                 RETVAL_FALSE;
    2886             :         }
    2887             : }
    2888             : /* }}} */
    2889             : 
    2890             : /* {{{ proto string mb_substr(string str, int start [, int length [, string encoding]])
    2891             :    Returns part of a string */
    2892         304 : PHP_FUNCTION(mb_substr)
    2893             : {
    2894         304 :         char *str, *encoding = NULL;
    2895             :         zend_long from, len;
    2896             :         int mblen;
    2897             :         size_t str_len, encoding_len;
    2898         304 :         zend_bool len_is_null = 1;
    2899             :         mbfl_string string, result, *ret;
    2900             : 
    2901         304 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl|l!s", &str, &str_len, &from, &len, &len_is_null, &encoding, &encoding_len) == FAILURE) {
    2902           4 :                 return;
    2903             :         }
    2904             : 
    2905         300 :         mbfl_string_init(&string);
    2906         300 :         string.no_language = MBSTRG(language);
    2907         300 :         string.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2908             : 
    2909         300 :         if (encoding) {
    2910         219 :                 string.no_encoding = mbfl_name2no_encoding(encoding);
    2911         219 :                 if (string.no_encoding == mbfl_no_encoding_invalid) {
    2912          20 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", encoding);
    2913          20 :                         RETURN_FALSE;
    2914             :                 }
    2915             :         }
    2916             : 
    2917         280 :         string.val = (unsigned char *)str;
    2918         280 :         string.len = str_len;
    2919             : 
    2920         280 :         if (len_is_null) {
    2921           2 :                 len = str_len;
    2922             :         }
    2923             : 
    2924             :         /* measures length */
    2925         280 :         mblen = 0;
    2926         280 :         if (from < 0 || len < 0) {
    2927          49 :                 mblen = mbfl_strlen(&string);
    2928             :         }
    2929             : 
    2930             :         /* if "from" position is negative, count start position from the end
    2931             :          * of the string
    2932             :          */
    2933         280 :         if (from < 0) {
    2934          25 :                 from = mblen + from;
    2935          25 :                 if (from < 0) {
    2936          17 :                         from = 0;
    2937             :                 }
    2938             :         }
    2939             : 
    2940             :         /* if "length" position is negative, set it to the length
    2941             :          * needed to stop that many chars from the end of the string
    2942             :          */
    2943         280 :         if (len < 0) {
    2944          24 :                 len = (mblen - from) + len;
    2945          24 :                 if (len < 0) {
    2946          16 :                         len = 0;
    2947             :                 }
    2948             :         }
    2949             : 
    2950         280 :         if (((MBSTRG(func_overload) & MB_OVERLOAD_STRING) == MB_OVERLOAD_STRING)
    2951           0 :                 && (from >= mbfl_strlen(&string))) {
    2952           0 :                 RETURN_FALSE;
    2953             :         }
    2954             : 
    2955         280 :         if (from > INT_MAX) {
    2956           2 :                 from = INT_MAX;
    2957             :         }
    2958         280 :         if (len > INT_MAX) {
    2959           1 :                 len = INT_MAX;
    2960             :         }
    2961             : 
    2962         280 :         ret = mbfl_substr(&string, &result, from, len);
    2963         280 :         if (NULL == ret) {
    2964           0 :                 RETURN_FALSE;
    2965             :         }
    2966             : 
    2967             :         // TODO: avoid reallocation ???
    2968         560 :         RETVAL_STRINGL((char *)ret->val, ret->len); /* the string is already strdup()'ed */
    2969         280 :         efree(ret->val);
    2970             : }
    2971             : /* }}} */
    2972             : 
    2973             : /* {{{ proto string mb_strcut(string str, int start [, int length [, string encoding]])
    2974             :    Returns part of a string */
    2975          18 : PHP_FUNCTION(mb_strcut)
    2976             : {
    2977          18 :         char *encoding = NULL;
    2978             :         zend_long from, len;
    2979             :         size_t encoding_len, string_len;
    2980          18 :         zend_bool len_is_null = 1;
    2981             :         mbfl_string string, result, *ret;
    2982             : 
    2983          18 :         mbfl_string_init(&string);
    2984          18 :         string.no_language = MBSTRG(language);
    2985          18 :         string.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2986             : 
    2987          18 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl|l!s", (char **)&string.val, &string_len, &from, &len, &len_is_null, &encoding, &encoding_len) == FAILURE) {
    2988           0 :                 return;
    2989             :         }
    2990             : 
    2991          18 :         if (ZEND_SIZE_T_UINT_OVFL(string_len)) {
    2992           0 :                         php_error_docref(NULL, E_WARNING, "String length overflows the max allowed length of %u", UINT_MAX);
    2993           0 :                         return;
    2994             :         }
    2995             : 
    2996          18 :         string.len = (uint32_t)string_len;
    2997             : 
    2998          18 :         if (encoding) {
    2999          11 :                 string.no_encoding = mbfl_name2no_encoding(encoding);
    3000          11 :                 if (string.no_encoding == mbfl_no_encoding_invalid) {
    3001           0 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", encoding);
    3002           0 :                         RETURN_FALSE;
    3003             :                 }
    3004             :         }
    3005             : 
    3006          18 :         if (len_is_null) {
    3007           1 :                 len = string.len;
    3008             :         }
    3009             : 
    3010             :         /* if "from" position is negative, count start position from the end
    3011             :          * of the string
    3012             :          */
    3013          18 :         if (from < 0) {
    3014           1 :                 from = string.len + from;
    3015           1 :                 if (from < 0) {
    3016           1 :                         from = 0;
    3017             :                 }
    3018             :         }
    3019             : 
    3020             :         /* if "length" position is negative, set it to the length
    3021             :          * needed to stop that many chars from the end of the string
    3022             :          */
    3023          18 :         if (len < 0) {
    3024           0 :                 len = (string.len - from) + len;
    3025           0 :                 if (len < 0) {
    3026           0 :                         len = 0;
    3027             :                 }
    3028             :         }
    3029             : 
    3030          18 :         if ((unsigned int)from > string.len) {
    3031           2 :                 RETURN_FALSE;
    3032             :         }
    3033             : 
    3034          16 :         ret = mbfl_strcut(&string, &result, from, len);
    3035          16 :         if (ret == NULL) {
    3036           0 :                 RETURN_FALSE;
    3037             :         }
    3038             : 
    3039             :         // TODO: avoid reallocation ???
    3040          32 :         RETVAL_STRINGL((char *)ret->val, ret->len); /* the string is already strdup()'ed */
    3041          16 :         efree(ret->val);
    3042             : }
    3043             : /* }}} */
    3044             : 
    3045             : /* {{{ proto int mb_strwidth(string str [, string encoding])
    3046             :    Gets terminal width of a string */
    3047        8258 : PHP_FUNCTION(mb_strwidth)
    3048             : {
    3049             :         int n;
    3050             :         mbfl_string string;
    3051        8258 :         char *enc_name = NULL;
    3052             :         size_t enc_name_len, string_len;
    3053             : 
    3054        8258 :         mbfl_string_init(&string);
    3055             : 
    3056        8258 :         string.no_language = MBSTRG(language);
    3057        8258 :         string.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    3058             : 
    3059        8258 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s", (char **)&string.val, &string_len, &enc_name, &enc_name_len) == FAILURE) {
    3060           0 :                 return;
    3061             :         }
    3062             : 
    3063        8258 :         if (ZEND_SIZE_T_UINT_OVFL(string_len)) {
    3064           0 :                         php_error_docref(NULL, E_WARNING, "String length overflows the max allowed length of %u", UINT_MAX);
    3065           0 :                         return;
    3066             :         }
    3067             : 
    3068        8258 :         string.len = (uint32_t)string_len;
    3069             : 
    3070        8258 :         if (enc_name != NULL) {
    3071        8258 :                 string.no_encoding = mbfl_name2no_encoding(enc_name);
    3072        8258 :                 if (string.no_encoding == mbfl_no_encoding_invalid) {
    3073           0 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", enc_name);
    3074           0 :                         RETURN_FALSE;
    3075             :                 }
    3076             :         }
    3077             : 
    3078        8258 :         n = mbfl_strwidth(&string);
    3079        8258 :         if (n >= 0) {
    3080        8258 :                 RETVAL_LONG(n);
    3081             :         } else {
    3082           0 :                 RETVAL_FALSE;
    3083             :         }
    3084             : }
    3085             : /* }}} */
    3086             : 
    3087             : /* {{{ proto string mb_strimwidth(string str, int start, int width [, string trimmarker [, string encoding]])
    3088             :    Trim the string in terminal width */
    3089          14 : PHP_FUNCTION(mb_strimwidth)
    3090             : {
    3091          14 :         char *str, *trimmarker = NULL, *encoding = NULL;
    3092             :         zend_long from, width, swidth;
    3093             :         size_t str_len, trimmarker_len, encoding_len;
    3094             :         mbfl_string string, result, marker, *ret;
    3095             : 
    3096          14 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sll|ss", &str, &str_len, &from, &width, &trimmarker, &trimmarker_len, &encoding, &encoding_len) == FAILURE) {
    3097           0 :                 return;
    3098             :         }
    3099             : 
    3100          14 :         mbfl_string_init(&string);
    3101          14 :         mbfl_string_init(&marker);
    3102          14 :         string.no_language = MBSTRG(language);
    3103          14 :         string.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    3104          14 :         marker.no_language = MBSTRG(language);
    3105          14 :         marker.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    3106          14 :         marker.val = NULL;
    3107          14 :         marker.len = 0;
    3108             : 
    3109          14 :         if (encoding) {
    3110          14 :                 string.no_encoding = marker.no_encoding = mbfl_name2no_encoding(encoding);
    3111          14 :                 if (string.no_encoding == mbfl_no_encoding_invalid) {
    3112           0 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", encoding);
    3113           0 :                         RETURN_FALSE;
    3114             :                 }
    3115             :         }
    3116             : 
    3117          14 :         string.val = (unsigned char *)str;
    3118          14 :         string.len = str_len;
    3119             : 
    3120          14 :         if ((from < 0) || (width < 0)) {
    3121           6 :                 swidth = mbfl_strwidth(&string);
    3122             :         }
    3123             : 
    3124          14 :         if (from < 0) {
    3125           4 :                 from += swidth;
    3126             :         }
    3127             :                 
    3128          14 :         if (from < 0 || (size_t)from > str_len) {
    3129           2 :                 php_error_docref(NULL, E_WARNING, "Start position is out of range");
    3130           2 :                 RETURN_FALSE;
    3131             :         }
    3132             : 
    3133          12 :         if (width < 0) {
    3134           4 :                 width = swidth + width - from;
    3135             :         }
    3136             : 
    3137          12 :         if (width < 0) {
    3138           2 :                 php_error_docref(NULL, E_WARNING, "Width is out of range");
    3139           2 :                 RETURN_FALSE;
    3140             :         }
    3141             : 
    3142          10 :         if (trimmarker) {
    3143          10 :                 marker.val = (unsigned char *)trimmarker;
    3144          10 :                 marker.len = trimmarker_len;
    3145             :         }
    3146             : 
    3147          10 :         ret = mbfl_strimwidth(&string, &marker, &result, from, width);
    3148             : 
    3149          10 :         if (ret == NULL) {
    3150           0 :                 RETURN_FALSE;
    3151             :         }
    3152             :         // TODO: avoid reallocation ???
    3153          20 :         RETVAL_STRINGL((char *)ret->val, ret->len); /* the string is already strdup()'ed */
    3154          10 :         efree(ret->val);
    3155             : }
    3156             : /* }}} */
    3157             : 
    3158             : 
    3159             : /* See mbfl_no_encoding definition for list of unsupported encodings */
    3160          10 : static inline zend_bool php_mb_is_unsupported_no_encoding(enum mbfl_no_encoding no_enc)
    3161             : {
    3162          10 :         return ((no_enc >= mbfl_no_encoding_invalid && no_enc <= mbfl_no_encoding_qprint)
    3163             :                         || (no_enc >= mbfl_no_encoding_utf7 && no_enc <= mbfl_no_encoding_utf7imap)
    3164             :                         || (no_enc >= mbfl_no_encoding_jis && no_enc <= mbfl_no_encoding_2022jpms)
    3165             :                         || (no_enc >= mbfl_no_encoding_cp50220 && no_enc <= mbfl_no_encoding_cp50222));
    3166             : }
    3167             : 
    3168             : 
    3169             : /* See mbfl_no_encoding definition for list of unicode encodings */
    3170      103427 : static inline zend_bool php_mb_is_no_encoding_unicode(enum mbfl_no_encoding no_enc)
    3171             : {
    3172      103427 :         return (no_enc >= mbfl_no_encoding_ucs4 && no_enc <= mbfl_no_encoding_utf8_sb);
    3173             : }
    3174             : 
    3175             : 
    3176             : /* See mbfl_no_encoding definition for list of UTF-8 encodings */
    3177       93561 : static inline zend_bool php_mb_is_no_encoding_utf8(enum mbfl_no_encoding no_enc)
    3178             : {
    3179       93561 :         return (no_enc >= mbfl_no_encoding_utf8 && no_enc <= mbfl_no_encoding_utf8_sb);
    3180             : }
    3181             : 
    3182             : 
    3183             : /* {{{ MBSTRING_API char *php_mb_convert_encoding() */
    3184       95176 : MBSTRING_API char *php_mb_convert_encoding(const char *input, size_t length, const char *_to_encoding, const char *_from_encodings, size_t *output_len)
    3185             : {
    3186             :         mbfl_string string, result, *ret;
    3187             :         const mbfl_encoding *from_encoding, *to_encoding;
    3188             :         mbfl_buffer_converter *convd;
    3189             :         size_t size;
    3190             :         const mbfl_encoding **list;
    3191       95176 :         char *output=NULL;
    3192             : 
    3193       95176 :         if (output_len) {
    3194       95176 :                 *output_len = 0;
    3195             :         }
    3196       95176 :         if (!input) {
    3197           0 :                 return NULL;
    3198             :         }
    3199             :         /* new encoding */
    3200      190331 :         if (_to_encoding && strlen(_to_encoding)) {
    3201       95168 :                 to_encoding = mbfl_name2encoding(_to_encoding);
    3202       95168 :                 if (!to_encoding) {
    3203          13 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", _to_encoding);
    3204          13 :                         return NULL;
    3205             :                 }
    3206             :         } else {
    3207           8 :                 to_encoding = MBSTRG(current_internal_encoding);
    3208             :         }
    3209             : 
    3210             :         /* initialize string */
    3211       95163 :         mbfl_string_init(&string);
    3212       95163 :         mbfl_string_init(&result);
    3213       95163 :         from_encoding = MBSTRG(current_internal_encoding);
    3214       95163 :         string.no_encoding = from_encoding->no_encoding;
    3215       95163 :         string.no_language = MBSTRG(language);
    3216       95163 :         string.val = (unsigned char *)input;
    3217       95163 :         string.len = length;
    3218             : 
    3219             :         /* pre-conversion encoding */
    3220       95163 :         if (_from_encodings) {
    3221       15149 :                 list = NULL;
    3222       15149 :                 size = 0;
    3223       15149 :                 php_mb_parse_encoding_list(_from_encodings, strlen(_from_encodings), &list, &size, 0);
    3224       15149 :                 if (size == 1) {
    3225       15140 :                         from_encoding = *list;
    3226       15140 :                         string.no_encoding = from_encoding->no_encoding;
    3227           9 :                 } else if (size > 1) {
    3228             :                         /* auto detect */
    3229           9 :                         from_encoding = mbfl_identify_encoding2(&string, list, size, MBSTRG(strict_detection));
    3230           9 :                         if (from_encoding) {
    3231           9 :                                 string.no_encoding = from_encoding->no_encoding;
    3232             :                         } else {
    3233           0 :                                 php_error_docref(NULL, E_WARNING, "Unable to detect character encoding");
    3234           0 :                                 from_encoding = &mbfl_encoding_pass;
    3235           0 :                                 to_encoding = from_encoding;
    3236           0 :                                 string.no_encoding = from_encoding->no_encoding;
    3237             :                         }
    3238             :                 } else {
    3239           0 :                         php_error_docref(NULL, E_WARNING, "Illegal character encoding specified");
    3240             :                 }
    3241       15149 :                 if (list != NULL) {
    3242       15149 :                         efree((void *)list);
    3243             :                 }
    3244             :         }
    3245             : 
    3246             :         /* initialize converter */
    3247       95163 :         convd = mbfl_buffer_converter_new2(from_encoding, to_encoding, string.len);
    3248       95163 :         if (convd == NULL) {
    3249           0 :                 php_error_docref(NULL, E_WARNING, "Unable to create character encoding converter");
    3250           0 :                 return NULL;
    3251             :         }
    3252       95163 :         mbfl_buffer_converter_illegal_mode(convd, MBSTRG(current_filter_illegal_mode));
    3253             : 
    3254       95163 :         if (string.no_encoding == MBSTRG(current_internal_encoding)->no_encoding) {
    3255       83285 :                 mbfl_buffer_converter_illegal_substchar(convd, MBSTRG(current_filter_illegal_substchar));
    3256       23378 :         } else if (php_mb_is_no_encoding_unicode(string.no_encoding) && php_mb_is_no_encoding_unicode(MBSTRG(current_internal_encoding)->no_encoding)) {
    3257             : 
    3258       11500 :                 if (php_mb_is_no_encoding_utf8(string.no_encoding)) {
    3259             : 
    3260          19 :                         if (MBSTRG(current_filter_illegal_substchar) > 0xd7ff &&
    3261           2 :                                 0xe000 > MBSTRG(current_filter_illegal_substchar)
    3262             :                         ) {
    3263           1 :                                 mbfl_buffer_converter_illegal_substchar(convd, 0x3f);
    3264             :                         } else {
    3265          15 :                                 mbfl_buffer_converter_illegal_substchar(convd, MBSTRG(current_filter_illegal_substchar));
    3266             :                         }
    3267             : 
    3268             :                 } else {
    3269       11484 :                         mbfl_buffer_converter_illegal_substchar(convd, MBSTRG(current_filter_illegal_substchar));
    3270             :                 }
    3271             : 
    3272             :         } else {
    3273         378 :                 mbfl_buffer_converter_illegal_substchar(convd, 0x3f);
    3274             :         }
    3275             : 
    3276             :         /* do it */
    3277       95163 :         ret = mbfl_buffer_converter_feed_result(convd, &string, &result);
    3278       95163 :         if (ret) {
    3279       95163 :                 if (output_len) {
    3280       95163 :                         *output_len = ret->len;
    3281             :                 }
    3282       95163 :                 output = (char *)ret->val;
    3283             :         }
    3284             : 
    3285       95163 :         MBSTRG(illegalchars) += mbfl_buffer_illegalchars(convd);
    3286       95163 :         mbfl_buffer_converter_delete(convd);
    3287       95163 :         return output;
    3288             : }
    3289             : /* }}} */
    3290             : 
    3291          12 : MBSTRING_API HashTable *php_mb_convert_encoding_recursive(HashTable *input, const char *_to_encoding, const char *_from_encodings)
    3292             : {
    3293             :         HashTable *output, *chash;
    3294             :         zend_long idx;
    3295             :         zend_string *key, *key_tmp;
    3296             :         zval *entry, entry_tmp;
    3297             :         size_t ckey_len, cval_len;
    3298             :         char *ckey, *cval;
    3299             : 
    3300          12 :         if (!input) {
    3301           0 :                 return NULL;
    3302             :         }
    3303             : 
    3304          12 :         output = (HashTable *)emalloc(sizeof(HashTable));
    3305          12 :         zend_hash_init(output, zend_hash_num_elements(input), NULL, ZVAL_PTR_DTOR, 0);
    3306          60 :         ZEND_HASH_FOREACH_KEY_VAL(input, idx, key, entry) {
    3307             :                 /* convert key */
    3308          24 :                 if (key) {
    3309           0 :                         ckey = php_mb_convert_encoding(ZSTR_VAL(key), ZSTR_LEN(key), _to_encoding, _from_encodings, &ckey_len);
    3310           0 :                         key_tmp = zend_string_init(ckey, ckey_len, 0);
    3311             :                 }
    3312             :                 /* convert value */
    3313             :                 ZEND_ASSERT(entry);
    3314          24 :                 switch(Z_TYPE_P(entry)) {
    3315             :                         case IS_STRING:
    3316          24 :                                 cval = php_mb_convert_encoding(Z_STRVAL_P(entry), Z_STRLEN_P(entry), _to_encoding, _from_encodings, &cval_len);
    3317          48 :                                 ZVAL_STRINGL(&entry_tmp, cval, cval_len);
    3318          24 :                                 efree(cval);
    3319          24 :                                 break;
    3320             :                         case IS_NULL:
    3321             :                         case IS_TRUE:
    3322             :                         case IS_FALSE:
    3323             :                         case IS_LONG:
    3324             :                         case IS_DOUBLE:
    3325           0 :                                 ZVAL_COPY(&entry_tmp, entry);
    3326           0 :                                 break;
    3327             :                         case IS_ARRAY:
    3328           0 :                                 chash = php_mb_convert_encoding_recursive(HASH_OF(entry), _to_encoding, _from_encodings);
    3329           0 :                                 array_init(&entry_tmp);
    3330           0 :                                 Z_ARRVAL(entry_tmp) = chash;
    3331           0 :                                 break;
    3332             :                         case IS_OBJECT:
    3333             :                         default:
    3334             :                                 zval_dtor(&entry_tmp);
    3335           0 :                                 php_error_docref(NULL, E_WARNING, "Object is not supported");
    3336           0 :                                 continue;
    3337             :                 }
    3338          24 :                 if (key) {
    3339           0 :                         zend_hash_add(output, key_tmp, &entry_tmp);
    3340             :                 } else {
    3341          24 :                         zend_hash_index_add(output, idx, &entry_tmp);
    3342             :                 }
    3343             :         } ZEND_HASH_FOREACH_END();
    3344             : 
    3345          12 :         return output;
    3346             : }
    3347             : /* }}} */
    3348             : 
    3349             : 
    3350             : /* {{{ proto string mb_convert_encoding(string str, string to-encoding [, mixed from-encoding])
    3351             :    Returns converted string in desired encoding */
    3352       12733 : PHP_FUNCTION(mb_convert_encoding)
    3353             : {
    3354             :         zval *input;
    3355             :         char *arg_new;
    3356             :         size_t new_len;
    3357       12733 :         zval *arg_old = NULL;
    3358             :         size_t size, l, n;
    3359       12733 :         char *_from_encodings = NULL, *ret, *s_free = NULL;
    3360             : 
    3361             :         zval *hash_entry;
    3362             :         HashTable *target_hash;
    3363             : 
    3364       12733 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "zs|z", &input, &arg_new, &new_len, &arg_old) == FAILURE) {
    3365           2 :                 return;
    3366             :         }
    3367             : 
    3368       25475 :         if (Z_TYPE_P(input) != IS_STRING && Z_TYPE_P(input) != IS_ARRAY) {
    3369           2 :                 convert_to_string(input);
    3370             :         }
    3371             : 
    3372       12731 :         if (arg_old) {
    3373       25434 :                 switch (Z_TYPE_P(arg_old)) {
    3374             :                         case IS_ARRAY:
    3375           3 :                                 target_hash = Z_ARRVAL_P(arg_old);
    3376           3 :                                 _from_encodings = NULL;
    3377             : 
    3378          27 :                                 ZEND_HASH_FOREACH_VAL(target_hash, hash_entry) {
    3379             : 
    3380          12 :                                         convert_to_string_ex(hash_entry);
    3381             : 
    3382          12 :                                         if ( _from_encodings) {
    3383           9 :                                                 l = strlen(_from_encodings);
    3384           9 :                                                 n = strlen(Z_STRVAL_P(hash_entry));
    3385           9 :                                                 _from_encodings = erealloc(_from_encodings, l+n+2);
    3386           9 :                                                 memcpy(_from_encodings + l, ",", 1);
    3387           9 :                                                 memcpy(_from_encodings + l + 1, Z_STRVAL_P(hash_entry), Z_STRLEN_P(hash_entry) + 1);
    3388             :                                         } else {
    3389           3 :                                                 _from_encodings = estrdup(Z_STRVAL_P(hash_entry));
    3390             :                                         }
    3391             :                                 } ZEND_HASH_FOREACH_END();
    3392             : 
    3393           3 :                                 if (_from_encodings != NULL && !strlen(_from_encodings)) {
    3394           0 :                                         efree(_from_encodings);
    3395           0 :                                         _from_encodings = NULL;
    3396             :                                 }
    3397           3 :                                 s_free = _from_encodings;
    3398           3 :                                 break;
    3399             :                         default:
    3400       25428 :                                 convert_to_string(arg_old);
    3401       12714 :                                 _from_encodings = Z_STRVAL_P(arg_old);
    3402             :                                 break;
    3403             :                         }
    3404             :         }
    3405             : 
    3406       25462 :         if (Z_TYPE_P(input) == IS_STRING) {
    3407             :                 /* new encoding */
    3408       12719 :                 ret = php_mb_convert_encoding(Z_STRVAL_P(input), Z_STRLEN_P(input), arg_new, _from_encodings, &size);
    3409       12719 :                 if (ret != NULL) {
    3410             :                         // TODO: avoid reallocation ???
    3411       25412 :                         RETVAL_STRINGL(ret, size);              /* the string is already strdup()'ed */
    3412       12706 :                         efree(ret);
    3413             :                 } else {
    3414          13 :                         RETVAL_FALSE;
    3415             :                 }
    3416       12719 :                 if (s_free) {
    3417           3 :                         efree(s_free);
    3418             :                 }
    3419             :         } else {
    3420             :                 HashTable *tmp;
    3421          24 :                 tmp = php_mb_convert_encoding_recursive(HASH_OF(input), arg_new, _from_encodings);
    3422          12 :                 RETURN_ARR(tmp);
    3423             :         }
    3424             : 
    3425       12719 :         return;
    3426             : }
    3427             : /* }}} */
    3428             : 
    3429             : /* {{{ proto string mb_convert_case(string sourcestring, int mode [, string encoding])
    3430             :    Returns a case-folded version of sourcestring */
    3431           1 : PHP_FUNCTION(mb_convert_case)
    3432             : {
    3433           1 :         const char *from_encoding = MBSTRG(current_internal_encoding)->mime_name;
    3434             :         char *str;
    3435             :         size_t str_len, from_encoding_len;
    3436           1 :         zend_long case_mode = 0;
    3437             :         char *newstr;
    3438             :         size_t ret_len;
    3439             : 
    3440           1 :         RETVAL_FALSE;
    3441           1 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl|s!", &str, &str_len,
    3442             :                                 &case_mode, &from_encoding, &from_encoding_len) == FAILURE) {
    3443           0 :                 return;
    3444             :         }
    3445             : 
    3446           1 :         newstr = php_unicode_convert_case(case_mode, str, (size_t) str_len, &ret_len, from_encoding);
    3447             : 
    3448           1 :         if (newstr) {
    3449             :                 // TODO: avoid reallocation ???
    3450           2 :                 RETVAL_STRINGL(newstr, ret_len);
    3451           1 :                 efree(newstr);
    3452             :         }
    3453             : }
    3454             : /* }}} */
    3455             : 
    3456             : /* {{{ proto string mb_strtoupper(string sourcestring [, string encoding])
    3457             :  *  Returns a uppercased version of sourcestring
    3458             :  */
    3459          68 : PHP_FUNCTION(mb_strtoupper)
    3460             : {
    3461          68 :         const char *from_encoding = MBSTRG(current_internal_encoding)->mime_name;
    3462             :         char *str;
    3463             :         size_t str_len, from_encoding_len;
    3464             :         char *newstr;
    3465             :         size_t ret_len;
    3466             : 
    3467          68 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s!", &str, &str_len,
    3468             :                                 &from_encoding, &from_encoding_len) == FAILURE) {
    3469           4 :                 return;
    3470             :         }
    3471          64 :         newstr = php_unicode_convert_case(PHP_UNICODE_CASE_UPPER, str, (size_t) str_len, &ret_len, from_encoding);
    3472             : 
    3473          64 :         if (newstr) {
    3474             :                 // TODO: avoid reallocation ???
    3475          78 :                 RETVAL_STRINGL(newstr, ret_len);
    3476          39 :                 efree(newstr);
    3477          39 :                 return;
    3478             :         }
    3479          25 :         RETURN_FALSE;
    3480             : }
    3481             : /* }}} */
    3482             : 
    3483             : /* {{{ proto string mb_strtolower(string sourcestring [, string encoding])
    3484             :  *  Returns a lowercased version of sourcestring
    3485             :  */
    3486          65 : PHP_FUNCTION(mb_strtolower)
    3487             : {
    3488          65 :         const char *from_encoding = MBSTRG(current_internal_encoding)->mime_name;
    3489             :         char *str;
    3490             :         size_t str_len, from_encoding_len;
    3491             :         char *newstr;
    3492             :         size_t ret_len;
    3493             : 
    3494          65 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s!", &str, &str_len,
    3495             :                                 &from_encoding, &from_encoding_len) == FAILURE) {
    3496           4 :                 return;
    3497             :         }
    3498          61 :         newstr = php_unicode_convert_case(PHP_UNICODE_CASE_LOWER, str, (size_t) str_len, &ret_len, from_encoding);
    3499             : 
    3500          61 :         if (newstr) {
    3501             :                 // TODO: avoid reallocation ???
    3502          72 :                 RETVAL_STRINGL(newstr, ret_len);
    3503          36 :                 efree(newstr);
    3504          36 :                 return;
    3505             :         }
    3506          25 :         RETURN_FALSE;
    3507             : }
    3508             : /* }}} */
    3509             : 
    3510             : /* {{{ proto string mb_detect_encoding(string str [, mixed encoding_list [, bool strict]])
    3511             :    Encodings of the given string is returned (as a string) */
    3512          18 : PHP_FUNCTION(mb_detect_encoding)
    3513             : {
    3514             :         char *str;
    3515             :         size_t str_len;
    3516          18 :         zend_bool strict=0;
    3517          18 :         zval *encoding_list = NULL;
    3518             : 
    3519             :         mbfl_string string;
    3520             :         const mbfl_encoding *ret;
    3521             :         const mbfl_encoding **elist, **list;
    3522             :         size_t size;
    3523             : 
    3524          18 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|z!b", &str, &str_len, &encoding_list, &strict) == FAILURE) {
    3525           1 :                 return;
    3526             :         }
    3527             : 
    3528             :         /* make encoding list */
    3529          17 :         list = NULL;
    3530          17 :         size = 0;
    3531          17 :         if (encoding_list) {
    3532          28 :                 switch (Z_TYPE_P(encoding_list)) {
    3533             :                 case IS_ARRAY:
    3534           3 :                         if (FAILURE == php_mb_parse_encoding_array(encoding_list, &list, &size, 0)) {
    3535           0 :                                 if (list) {
    3536           0 :                                         efree(list);
    3537           0 :                                         list = NULL;
    3538           0 :                                         size = 0;
    3539             :                                 }
    3540             :                         }
    3541           3 :                         break;
    3542             :                 default:
    3543          22 :                         convert_to_string(encoding_list);
    3544          11 :                         if (FAILURE == php_mb_parse_encoding_list(Z_STRVAL_P(encoding_list), Z_STRLEN_P(encoding_list), &list, &size, 0)) {
    3545           0 :                                 if (list) {
    3546           0 :                                         efree(list);
    3547           0 :                                         list = NULL;
    3548           0 :                                         size = 0;
    3549             :                                 }
    3550             :                         }
    3551             :                         break;
    3552             :                 }
    3553          14 :                 if (size <= 0) {
    3554           1 :                         php_error_docref(NULL, E_WARNING, "Illegal argument");
    3555             :                 }
    3556             :         }
    3557             : 
    3558          17 :         if (ZEND_NUM_ARGS() < 3) {
    3559          13 :                 strict = (zend_bool)MBSTRG(strict_detection);
    3560             :         }
    3561             : 
    3562          30 :         if (size > 0 && list != NULL) {
    3563          13 :                 elist = list;
    3564             :         } else {
    3565           4 :                 elist = MBSTRG(current_detect_order_list);
    3566           4 :                 size = MBSTRG(current_detect_order_list_size);
    3567             :         }
    3568             : 
    3569          17 :         mbfl_string_init(&string);
    3570          17 :         string.no_language = MBSTRG(language);
    3571          17 :         string.val = (unsigned char *)str;
    3572          17 :         string.len = str_len;
    3573          17 :         ret = mbfl_identify_encoding2(&string, elist, size, strict);
    3574             : 
    3575          17 :         if (list != NULL) {
    3576          13 :                 efree((void *)list);
    3577             :         }
    3578             : 
    3579          17 :         if (ret == NULL) {
    3580           3 :                 RETURN_FALSE;
    3581             :         }
    3582             : 
    3583          28 :         RETVAL_STRING((char *)ret->name);
    3584             : }
    3585             : /* }}} */
    3586             : 
    3587             : /* {{{ proto mixed mb_list_encodings()
    3588             :    Returns an array of all supported entity encodings */
    3589           4 : PHP_FUNCTION(mb_list_encodings)
    3590             : {
    3591             :         const mbfl_encoding **encodings;
    3592             :         const mbfl_encoding *encoding;
    3593             :         int i;
    3594             : 
    3595           4 :         if (zend_parse_parameters_none() == FAILURE) {
    3596           0 :                 return;
    3597             :         }
    3598             : 
    3599           4 :         array_init(return_value);
    3600           4 :         i = 0;
    3601           4 :         encodings = mbfl_get_supported_encodings();
    3602         356 :         while ((encoding = encodings[i++]) != NULL) {
    3603         348 :                 add_next_index_string(return_value, (char *) encoding->name);
    3604             :         }
    3605             : }
    3606             : /* }}} */
    3607             : 
    3608             : /* {{{ proto array mb_encoding_aliases(string encoding)
    3609             :    Returns an array of the aliases of a given encoding name */
    3610           4 : PHP_FUNCTION(mb_encoding_aliases)
    3611             : {
    3612             :         const mbfl_encoding *encoding;
    3613           4 :         char *name = NULL;
    3614             :         size_t name_len;
    3615             : 
    3616           4 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
    3617           1 :                 return;
    3618             :         }
    3619             : 
    3620           3 :         encoding = mbfl_name2encoding(name);
    3621           3 :         if (!encoding) {
    3622           0 :                 php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", name);
    3623           0 :                 RETURN_FALSE;
    3624             :         }
    3625             : 
    3626           3 :         array_init(return_value);
    3627           3 :         if (encoding->aliases != NULL) {
    3628             :                 const char **alias;
    3629          14 :                 for (alias = *encoding->aliases; *alias; ++alias) {
    3630          12 :                         add_next_index_string(return_value, (char *)*alias);
    3631             :                 }
    3632             :         }
    3633             : }
    3634             : /* }}} */
    3635             : 
    3636             : /* {{{ proto string mb_encode_mimeheader(string str [, string charset [, string transfer-encoding [, string linefeed [, int indent]]]])
    3637             :    Converts the string to MIME "encoded-word" in the format of =?charset?(B|Q)?encoded_string?= */
    3638         341 : PHP_FUNCTION(mb_encode_mimeheader)
    3639             : {
    3640             :         enum mbfl_no_encoding charset, transenc;
    3641             :         mbfl_string  string, result, *ret;
    3642         341 :         char *charset_name = NULL;
    3643             :         size_t charset_name_len;
    3644         341 :         char *trans_enc_name = NULL;
    3645             :         size_t trans_enc_name_len;
    3646         341 :         char *linefeed = "\r\n";
    3647             :         size_t linefeed_len, string_len;
    3648         341 :         zend_long indent = 0;
    3649             : 
    3650         341 :         mbfl_string_init(&string);
    3651         341 :         string.no_language = MBSTRG(language);
    3652         341 :         string.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    3653             : 
    3654         341 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|sssl", (char **)&string.val, &string_len, &charset_name, &charset_name_len, &trans_enc_name, &trans_enc_name_len, &linefeed, &linefeed_len, &indent) == FAILURE) {
    3655          11 :                 return;
    3656             :         }
    3657             : 
    3658         330 :         if (ZEND_SIZE_T_UINT_OVFL(string_len)) {
    3659           0 :                         php_error_docref(NULL, E_WARNING, "String length overflows the max allowed length of %u", UINT_MAX);
    3660           0 :                         return;
    3661             :         }
    3662             : 
    3663         330 :         string.len = (uint32_t)string_len;
    3664             : 
    3665         330 :         charset = mbfl_no_encoding_pass;
    3666         330 :         transenc = mbfl_no_encoding_base64;
    3667             : 
    3668         330 :         if (charset_name != NULL) {
    3669         330 :                 charset = mbfl_name2no_encoding(charset_name);
    3670         330 :                 if (charset == mbfl_no_encoding_invalid) {
    3671          19 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", charset_name);
    3672          19 :                         RETURN_FALSE;
    3673             :                 }
    3674             :         } else {
    3675           0 :                 const mbfl_language *lang = mbfl_no2language(MBSTRG(language));
    3676           0 :                 if (lang != NULL) {
    3677           0 :                         charset = lang->mail_charset;
    3678           0 :                         transenc = lang->mail_header_encoding;
    3679             :                 }
    3680             :         }
    3681             : 
    3682         311 :         if (trans_enc_name != NULL) {
    3683         490 :                 if (*trans_enc_name == 'B' || *trans_enc_name == 'b') {
    3684         179 :                         transenc = mbfl_no_encoding_base64;
    3685         132 :                 } else if (*trans_enc_name == 'Q' || *trans_enc_name == 'q') {
    3686         109 :                         transenc = mbfl_no_encoding_qprint;
    3687             :                 }
    3688             :         }
    3689             : 
    3690         311 :         mbfl_string_init(&result);
    3691         311 :         ret = mbfl_mime_header_encode(&string, &result, charset, transenc, linefeed, indent);
    3692         311 :         if (ret != NULL) {
    3693             :                 // TODO: avoid reallocation ???
    3694         622 :                 RETVAL_STRINGL((char *)ret->val, ret->len);       /* the string is already strdup()'ed */
    3695         311 :                 efree(ret->val);
    3696             :         } else {
    3697           0 :                 RETVAL_FALSE;
    3698             :         }
    3699             : }
    3700             : /* }}} */
    3701             : 
    3702             : /* {{{ proto string mb_decode_mimeheader(string string)
    3703             :    Decodes the MIME "encoded-word" in the string */
    3704          39 : PHP_FUNCTION(mb_decode_mimeheader)
    3705             : {
    3706             :         mbfl_string string, result, *ret;
    3707             :         size_t string_len;
    3708             : 
    3709          39 :         mbfl_string_init(&string);
    3710          39 :         string.no_language = MBSTRG(language);
    3711          39 :         string.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    3712             : 
    3713          39 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", (char **)&string.val, &string_len) == FAILURE) {
    3714           8 :                 return;
    3715             :         }
    3716             : 
    3717          31 :         if (ZEND_SIZE_T_UINT_OVFL(string_len)) {
    3718           0 :                         php_error_docref(NULL, E_WARNING, "String length overflows the max allowed length of %u", UINT_MAX);
    3719           0 :                         return;
    3720             :         }
    3721             : 
    3722          31 :         string.len = (uint32_t)string_len;
    3723             : 
    3724          31 :         mbfl_string_init(&result);
    3725          31 :         ret = mbfl_mime_header_decode(&string, &result, MBSTRG(current_internal_encoding)->no_encoding);
    3726          31 :         if (ret != NULL) {
    3727             :                 // TODO: avoid reallocation ???
    3728          62 :                 RETVAL_STRINGL((char *)ret->val, ret->len);       /* the string is already strdup()'ed */
    3729          31 :                 efree(ret->val);
    3730             :         } else {
    3731           0 :                 RETVAL_FALSE;
    3732             :         }
    3733             : }
    3734             : /* }}} */
    3735             : 
    3736             : /* {{{ proto string mb_convert_kana(string str [, string option] [, string encoding])
    3737             :    Conversion between full-width character and half-width character (Japanese) */
    3738          10 : PHP_FUNCTION(mb_convert_kana)
    3739             : {
    3740             :         int opt, i;
    3741             :         mbfl_string string, result, *ret;
    3742          10 :         char *optstr = NULL;
    3743             :         size_t optstr_len;
    3744          10 :         char *encname = NULL;
    3745             :         size_t encname_len, string_len;
    3746             : 
    3747          10 :         mbfl_string_init(&string);
    3748          10 :         string.no_language = MBSTRG(language);
    3749          10 :         string.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    3750             : 
    3751          10 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|ss", (char **)&string.val, &string_len, &optstr, &optstr_len, &encname, &encname_len) == FAILURE) {
    3752           0 :                 return;
    3753             :         }
    3754             : 
    3755          10 :         if (ZEND_SIZE_T_UINT_OVFL(string_len)) {
    3756           0 :                         php_error_docref(NULL, E_WARNING, "String length overflows the max allowed length of %u", UINT_MAX);
    3757           0 :                         return;
    3758             :         }
    3759             : 
    3760          10 :         string.len = (uint32_t)string_len;
    3761             : 
    3762             :         /* option */
    3763          10 :         if (optstr != NULL) {
    3764          10 :                 char *p = optstr;
    3765          10 :                 int n = optstr_len;
    3766          10 :                 i = 0;
    3767          10 :                 opt = 0;
    3768          60 :                 while (i < n) {
    3769          40 :                         i++;
    3770          40 :                         switch (*p++) {
    3771             :                         case 'A':
    3772           5 :                                 opt |= 0x1;
    3773           5 :                                 break;
    3774             :                         case 'a':
    3775           5 :                                 opt |= 0x10;
    3776           5 :                                 break;
    3777             :                         case 'R':
    3778           0 :                                 opt |= 0x2;
    3779           0 :                                 break;
    3780             :                         case 'r':
    3781           0 :                                 opt |= 0x20;
    3782           0 :                                 break;
    3783             :                         case 'N':
    3784           0 :                                 opt |= 0x4;
    3785           0 :                                 break;
    3786             :                         case 'n':
    3787           0 :                                 opt |= 0x40;
    3788           0 :                                 break;
    3789             :                         case 'S':
    3790           0 :                                 opt |= 0x8;
    3791           0 :                                 break;
    3792             :                         case 's':
    3793           0 :                                 opt |= 0x80;
    3794           0 :                                 break;
    3795             :                         case 'K':
    3796           5 :                                 opt |= 0x100;
    3797           5 :                                 break;
    3798             :                         case 'k':
    3799           5 :                                 opt |= 0x1000;
    3800           5 :                                 break;
    3801             :                         case 'H':
    3802           5 :                                 opt |= 0x200;
    3803           5 :                                 break;
    3804             :                         case 'h':
    3805           5 :                                 opt |= 0x2000;
    3806           5 :                                 break;
    3807             :                         case 'V':
    3808           0 :                                 opt |= 0x800;
    3809           0 :                                 break;
    3810             :                         case 'C':
    3811           0 :                                 opt |= 0x10000;
    3812           0 :                                 break;
    3813             :                         case 'c':
    3814           0 :                                 opt |= 0x20000;
    3815           0 :                                 break;
    3816             :                         case 'M':
    3817           0 :                                 opt |= 0x100000;
    3818           0 :                                 break;
    3819             :                         case 'm':
    3820           0 :                                 opt |= 0x200000;
    3821             :                                 break;
    3822             :                         }
    3823             :                 }
    3824             :         } else {
    3825           0 :                 opt = 0x900;
    3826             :         }
    3827             : 
    3828             :         /* encoding */
    3829          10 :         if (encname != NULL) {
    3830          10 :                 string.no_encoding = mbfl_name2no_encoding(encname);
    3831          10 :                 if (string.no_encoding == mbfl_no_encoding_invalid) {
    3832           0 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", encname);
    3833           0 :                         RETURN_FALSE;
    3834             :                 }
    3835             :         }
    3836             : 
    3837          10 :         ret = mbfl_ja_jp_hantozen(&string, &result, opt);
    3838          10 :         if (ret != NULL) {
    3839             :                 // TODO: avoid reallocation ???
    3840          20 :                 RETVAL_STRINGL((char *)ret->val, ret->len);               /* the string is already strdup()'ed */
    3841          10 :                 efree(ret->val);
    3842             :         } else {
    3843           0 :                 RETVAL_FALSE;
    3844             :         }
    3845             : }
    3846             : /* }}} */
    3847             : 
    3848             : #define PHP_MBSTR_STACK_BLOCK_SIZE 32
    3849             : 
    3850             : /* {{{ proto string mb_convert_variables(string to-encoding, mixed from-encoding, mixed vars [, ...])
    3851             :    Converts the string resource in variables to desired encoding */
    3852          21 : PHP_FUNCTION(mb_convert_variables)
    3853             : {
    3854             :         zval *args, *stack, *var, *hash_entry, *hash_entry_ptr, *zfrom_enc;
    3855             :         HashTable *target_hash;
    3856             :         mbfl_string string, result, *ret;
    3857             :         const mbfl_encoding *from_encoding, *to_encoding;
    3858             :         mbfl_encoding_detector *identd;
    3859             :         mbfl_buffer_converter *convd;
    3860             :         int n, argc, stack_level, stack_max;
    3861             :         size_t to_enc_len;
    3862             :         size_t elistsz;
    3863             :         const mbfl_encoding **elist;
    3864             :         char *to_enc;
    3865             :         void *ptmp;
    3866          21 :         int recursion_error = 0;
    3867             : 
    3868          21 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz+", &to_enc, &to_enc_len, &zfrom_enc, &args, &argc) == FAILURE) {
    3869           0 :                 return;
    3870             :         }
    3871             : 
    3872             :         /* new encoding */
    3873          21 :         to_encoding = mbfl_name2encoding(to_enc);
    3874          21 :         if (!to_encoding) {
    3875           0 :                 php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", to_enc);
    3876           0 :                 RETURN_FALSE;
    3877             :         }
    3878             : 
    3879             :         /* initialize string */
    3880          21 :         mbfl_string_init(&string);
    3881          21 :         mbfl_string_init(&result);
    3882          21 :         from_encoding = MBSTRG(current_internal_encoding);
    3883          21 :         string.no_encoding = from_encoding->no_encoding;
    3884          21 :         string.no_language = MBSTRG(language);
    3885             : 
    3886             :         /* pre-conversion encoding */
    3887          21 :         elist = NULL;
    3888          21 :         elistsz = 0;
    3889          42 :         switch (Z_TYPE_P(zfrom_enc)) {
    3890             :                 case IS_ARRAY:
    3891           0 :                         php_mb_parse_encoding_array(zfrom_enc, &elist, &elistsz, 0);
    3892           0 :                         break;
    3893             :                 default:
    3894          42 :                         convert_to_string_ex(zfrom_enc);
    3895          21 :                         php_mb_parse_encoding_list(Z_STRVAL_P(zfrom_enc), Z_STRLEN_P(zfrom_enc), &elist, &elistsz, 0);
    3896             :                         break;
    3897             :         }
    3898             : 
    3899          21 :         if (elistsz <= 0) {
    3900           0 :                 from_encoding = &mbfl_encoding_pass;
    3901          21 :         } else if (elistsz == 1) {
    3902          14 :                 from_encoding = *elist;
    3903             :         } else {
    3904             :                 /* auto detect */
    3905           7 :                 from_encoding = NULL;
    3906           7 :                 stack_max = PHP_MBSTR_STACK_BLOCK_SIZE;
    3907           7 :                 stack = (zval *)safe_emalloc(stack_max, sizeof(zval), 0);
    3908           7 :                 stack_level = 0;
    3909           7 :                 identd = mbfl_encoding_detector_new2(elist, elistsz, MBSTRG(strict_detection));
    3910           7 :                 if (identd != NULL) {
    3911           7 :                         n = 0;
    3912          14 :                         while (n < argc || stack_level > 0) {
    3913           7 :                                 if (stack_level <= 0) {
    3914           7 :                                         var = &args[n++];
    3915           7 :                                         ZVAL_DEREF(var);
    3916          12 :                                         SEPARATE_ZVAL_NOREF(var);
    3917          11 :                                         if (Z_TYPE_P(var) == IS_ARRAY || Z_TYPE_P(var) == IS_OBJECT) {
    3918           7 :                                                 target_hash = HASH_OF(var);
    3919           5 :                                                 if (target_hash != NULL) {
    3920           5 :                                                         zend_hash_internal_pointer_reset(target_hash);
    3921             :                                                 }
    3922             :                                         }
    3923             :                                 } else {
    3924           0 :                                         stack_level--;
    3925           0 :                                         var = &stack[stack_level];
    3926             :                                 }
    3927          11 :                                 if (Z_TYPE_P(var) == IS_ARRAY || Z_TYPE_P(var) == IS_OBJECT) {
    3928           7 :                                         target_hash = HASH_OF(var);
    3929           5 :                                         if (target_hash != NULL) {
    3930          11 :                                                 while ((hash_entry = zend_hash_get_current_data(target_hash)) != NULL) {
    3931           6 :                                                         if (++target_hash->u.v.nApplyCount > 1) {
    3932           1 :                                                                 --target_hash->u.v.nApplyCount;
    3933           1 :                                                                 recursion_error = 1;
    3934           1 :                                                                 goto detect_end;
    3935             :                                                         }
    3936           5 :                                                         zend_hash_move_forward(target_hash);
    3937           5 :                                                         if (Z_TYPE_P(hash_entry) == IS_INDIRECT) {
    3938           2 :                                                                 hash_entry = Z_INDIRECT_P(hash_entry);
    3939             :                                                         }
    3940           5 :                                                         ZVAL_DEREF(hash_entry);
    3941           9 :                                                         if (Z_TYPE_P(hash_entry) == IS_ARRAY || Z_TYPE_P(hash_entry) == IS_OBJECT) {
    3942           1 :                                                                 if (stack_level >= stack_max) {
    3943           0 :                                                                         stack_max += PHP_MBSTR_STACK_BLOCK_SIZE;
    3944           0 :                                                                         ptmp = erealloc(stack, sizeof(zval) * stack_max);
    3945           0 :                                                                         stack = (zval *)ptmp;
    3946             :                                                                 }
    3947           1 :                                                                 ZVAL_COPY_VALUE(&stack[stack_level], var);
    3948           1 :                                                                 stack_level++;
    3949           1 :                                                                 var = hash_entry;
    3950           1 :                                                                 target_hash = HASH_OF(var);
    3951           1 :                                                                 if (target_hash != NULL) {
    3952           1 :                                                                         zend_hash_internal_pointer_reset(target_hash);
    3953           1 :                                                                         continue;
    3954             :                                                                 }
    3955           4 :                                                         } else if (Z_TYPE_P(hash_entry) == IS_STRING) {
    3956           4 :                                                                 string.val = (unsigned char *)Z_STRVAL_P(hash_entry);
    3957           4 :                                                                 string.len = Z_STRLEN_P(hash_entry);
    3958           4 :                                                                 if (mbfl_encoding_detector_feed(identd, &string)) {
    3959           4 :                                                                         goto detect_end;                /* complete detecting */
    3960             :                                                                 }
    3961             :                                                         }
    3962             :                                                 }
    3963             :                                         }
    3964           2 :                                 } else if (Z_TYPE_P(var) == IS_STRING) {
    3965           2 :                                         string.val = (unsigned char *)Z_STRVAL_P(var);
    3966           2 :                                         string.len = Z_STRLEN_P(var);
    3967           2 :                                         if (mbfl_encoding_detector_feed(identd, &string)) {
    3968           2 :                                                 goto detect_end;                /* complete detecting */
    3969             :                                         }
    3970             :                                 }
    3971             :                         }
    3972             : detect_end:
    3973           7 :                         from_encoding = mbfl_encoding_detector_judge2(identd);
    3974           7 :                         mbfl_encoding_detector_delete(identd);
    3975             :                 }
    3976           7 :                 if (recursion_error) {
    3977           3 :                         while(stack_level-- && (var = &stack[stack_level])) {
    3978           1 :                                 if (HASH_OF(var)->u.v.nApplyCount > 1) {
    3979           0 :                                         HASH_OF(var)->u.v.nApplyCount--;
    3980             :                                 }
    3981             :                         }
    3982           1 :                         efree(stack);
    3983           1 :                         if (elist != NULL) {
    3984           1 :                                 efree((void *)elist);
    3985             :                         }
    3986           1 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot handle recursive references");
    3987           1 :                         RETURN_FALSE;
    3988             :                 }
    3989           6 :                 efree(stack);
    3990             : 
    3991           6 :                 if (!from_encoding) {
    3992           0 :                         php_error_docref(NULL, E_WARNING, "Unable to detect encoding");
    3993           0 :                         from_encoding = &mbfl_encoding_pass;
    3994             :                 }
    3995             :         }
    3996          20 :         if (elist != NULL) {
    3997          20 :                 efree((void *)elist);
    3998             :         }
    3999             :         /* create converter */
    4000          20 :         convd = NULL;
    4001          20 :         if (from_encoding != &mbfl_encoding_pass) {
    4002          20 :                 convd = mbfl_buffer_converter_new2(from_encoding, to_encoding, 0);
    4003          20 :                 if (convd == NULL) {
    4004           0 :                         php_error_docref(NULL, E_WARNING, "Unable to create converter");
    4005           0 :                         RETURN_FALSE;
    4006             :                 }
    4007          20 :                 mbfl_buffer_converter_illegal_mode(convd, MBSTRG(current_filter_illegal_mode));
    4008          20 :                 mbfl_buffer_converter_illegal_substchar(convd, MBSTRG(current_filter_illegal_substchar));
    4009             :         }
    4010             : 
    4011             :         /* convert */
    4012          20 :         if (convd != NULL) {
    4013          20 :                 stack_max = PHP_MBSTR_STACK_BLOCK_SIZE;
    4014          20 :                 stack = (zval*)safe_emalloc(stack_max, sizeof(zval), 0);
    4015          20 :                 stack_level = 0;
    4016          20 :                 n = 0;
    4017          65 :                 while (n < argc || stack_level > 0) {
    4018          27 :                         if (stack_level <= 0) {
    4019          26 :                                 var = &args[n++];
    4020          26 :                                 ZVAL_DEREF(var);
    4021          45 :                                 SEPARATE_ZVAL_NOREF(var);
    4022          41 :                                 if (Z_TYPE_P(var) == IS_ARRAY || Z_TYPE_P(var) == IS_OBJECT) {
    4023          17 :                                         target_hash = HASH_OF(var);
    4024          14 :                                         if (target_hash != NULL) {
    4025          14 :                                                 zend_hash_internal_pointer_reset(target_hash);
    4026             :                                         }
    4027             :                                 }
    4028             :                         } else {
    4029           1 :                                 stack_level--;
    4030           1 :                                 var = &stack[stack_level];
    4031             :                         }
    4032          55 :                         if (Z_TYPE_P(var) == IS_ARRAY || Z_TYPE_P(var) == IS_OBJECT) {
    4033          18 :                                 target_hash = HASH_OF(var);
    4034          15 :                                 if (target_hash != NULL) {
    4035          67 :                                         while ((hash_entry_ptr = zend_hash_get_current_data(target_hash)) != NULL) {
    4036          39 :                                                 zend_hash_move_forward(target_hash);
    4037          39 :                                                 if (Z_TYPE_P(hash_entry_ptr) == IS_INDIRECT) {
    4038           9 :                                                         hash_entry_ptr = Z_INDIRECT_P(hash_entry_ptr);
    4039             :                                                 }
    4040          39 :                                                 hash_entry = hash_entry_ptr;
    4041          39 :                                                 ZVAL_DEREF(hash_entry);
    4042          74 :                                                 if (Z_TYPE_P(hash_entry) == IS_ARRAY || Z_TYPE_P(hash_entry) == IS_OBJECT) {
    4043           4 :                                                         if (++(HASH_OF(hash_entry)->u.v.nApplyCount) > 1) {
    4044           2 :                                                                 --(HASH_OF(hash_entry)->u.v.nApplyCount);
    4045           2 :                                                                 recursion_error = 1;
    4046           2 :                                                                 goto conv_end;
    4047             :                                                         }
    4048           2 :                                                         if (stack_level >= stack_max) {
    4049           0 :                                                                 stack_max += PHP_MBSTR_STACK_BLOCK_SIZE;
    4050           0 :                                                                 ptmp = erealloc(stack, sizeof(zval) * stack_max);
    4051           0 :                                                                 stack = (zval *)ptmp;
    4052             :                                                         }
    4053           2 :                                                         ZVAL_COPY_VALUE(&stack[stack_level], var);
    4054           2 :                                                         stack_level++;
    4055           2 :                                                         var = hash_entry;
    4056           5 :                                                         SEPARATE_ZVAL(hash_entry);
    4057           2 :                                                         target_hash = HASH_OF(var);
    4058           2 :                                                         if (target_hash != NULL) {
    4059           2 :                                                                 zend_hash_internal_pointer_reset(target_hash);
    4060           2 :                                                                 continue;
    4061             :                                                         }
    4062          35 :                                                 } else if (Z_TYPE_P(hash_entry) == IS_STRING) {
    4063          35 :                                                         string.val = (unsigned char *)Z_STRVAL_P(hash_entry);
    4064          35 :                                                         string.len = Z_STRLEN_P(hash_entry);
    4065          35 :                                                         ret = mbfl_buffer_converter_feed_result(convd, &string, &result);
    4066          35 :                                                         if (ret != NULL) {
    4067          35 :                                                                 zval_ptr_dtor(hash_entry_ptr);
    4068             :                                                                 // TODO: avoid reallocation ???
    4069          70 :                                                                 ZVAL_STRINGL(hash_entry_ptr, (char *)ret->val, ret->len);
    4070          35 :                                                                 efree(ret->val);
    4071             :                                                         }
    4072             :                                                 }
    4073             :                                         }
    4074             :                                 }
    4075          12 :                         } else if (Z_TYPE_P(var) == IS_STRING) {
    4076          12 :                                 string.val = (unsigned char *)Z_STRVAL_P(var);
    4077          12 :                                 string.len = Z_STRLEN_P(var);
    4078          12 :                                 ret = mbfl_buffer_converter_feed_result(convd, &string, &result);
    4079          12 :                                 if (ret != NULL) {
    4080          12 :                                         zval_ptr_dtor(var);
    4081             :                                         // TODO: avoid reallocation ???
    4082          24 :                                         ZVAL_STRINGL(var, (char *)ret->val, ret->len);
    4083          12 :                                         efree(ret->val);
    4084             :                                 }
    4085             :                         }
    4086             :                 }
    4087             : 
    4088             : conv_end:
    4089          20 :                 MBSTRG(illegalchars) += mbfl_buffer_illegalchars(convd);
    4090          20 :                 mbfl_buffer_converter_delete(convd);
    4091             : 
    4092          20 :                 if (recursion_error) {
    4093           5 :                         while(stack_level-- && (var = &stack[stack_level])) {
    4094           1 :                                 if (HASH_OF(var)->u.v.nApplyCount > 1) {
    4095           0 :                                         HASH_OF(var)->u.v.nApplyCount--;
    4096             :                                 }
    4097             :                         }
    4098           2 :                         efree(stack);
    4099           2 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot handle recursive references");
    4100           2 :                         RETURN_FALSE;
    4101             :                 }
    4102          18 :                 efree(stack);
    4103             :         }
    4104             : 
    4105          18 :         if (from_encoding) {
    4106          36 :                 RETURN_STRING(from_encoding->name);
    4107             :         } else {
    4108           0 :                 RETURN_FALSE;
    4109             :         }
    4110             : }
    4111             : /* }}} */
    4112             : 
    4113             : /* {{{ HTML numeric entity */
    4114             : /* {{{ static void php_mb_numericentity_exec() */
    4115             : static void
    4116          14 : php_mb_numericentity_exec(INTERNAL_FUNCTION_PARAMETERS, int type)
    4117             : {
    4118          14 :         char *str, *encoding = NULL;
    4119             :         size_t str_len, encoding_len;
    4120             :         zval *zconvmap, *hash_entry;
    4121             :         HashTable *target_hash;
    4122          14 :         int i, *convmap, *mapelm, mapsize=0;
    4123          14 :         zend_bool is_hex = 0;
    4124             :         mbfl_string string, result, *ret;
    4125             :         enum mbfl_no_encoding no_encoding;
    4126             : 
    4127          14 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz|sb", &str, &str_len, &zconvmap, &encoding, &encoding_len, &is_hex) == FAILURE) {
    4128           0 :                 return;
    4129             :         }
    4130             : 
    4131          14 :         mbfl_string_init(&string);
    4132          14 :         string.no_language = MBSTRG(language);
    4133          14 :         string.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    4134          14 :         string.val = (unsigned char *)str;
    4135          14 :         string.len = str_len;
    4136             : 
    4137             :         /* encoding */
    4138          14 :         if (encoding && encoding_len > 0) {
    4139          14 :                 no_encoding = mbfl_name2no_encoding(encoding);
    4140          14 :                 if (no_encoding == mbfl_no_encoding_invalid) {
    4141           0 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", encoding);
    4142           0 :                         RETURN_FALSE;
    4143             :                 } else {
    4144          14 :                         string.no_encoding = no_encoding;
    4145             :                 }
    4146             :         }
    4147             : 
    4148          14 :         if (type == 0 && is_hex) {
    4149           0 :                 type = 2; /* output in hex format */
    4150             :         }
    4151             : 
    4152             :         /* conversion map */
    4153          14 :         convmap = NULL;
    4154          28 :         if (Z_TYPE_P(zconvmap) == IS_ARRAY) {
    4155          14 :                 target_hash = Z_ARRVAL_P(zconvmap);
    4156          14 :                 i = zend_hash_num_elements(target_hash);
    4157          14 :                 if (i > 0) {
    4158          14 :                         convmap = (int *)safe_emalloc(i, sizeof(int), 0);
    4159          14 :                         mapelm = convmap;
    4160          14 :                         mapsize = 0;
    4161         126 :                         ZEND_HASH_FOREACH_VAL(target_hash, hash_entry) {
    4162          56 :                                 convert_to_long_ex(hash_entry);
    4163          56 :                                 *mapelm++ = Z_LVAL_P(hash_entry);
    4164          56 :                                 mapsize++;
    4165             :                         } ZEND_HASH_FOREACH_END();
    4166             :                 }
    4167             :         }
    4168          14 :         if (convmap == NULL) {
    4169           0 :                 RETURN_FALSE;
    4170             :         }
    4171          14 :         mapsize /= 4;
    4172             : 
    4173          14 :         ret = mbfl_html_numeric_entity(&string, &result, convmap, mapsize, type);
    4174          14 :         if (ret != NULL) {
    4175             :                 // TODO: avoid reallocation ???
    4176          28 :                 RETVAL_STRINGL((char *)ret->val, ret->len);
    4177          14 :                 efree(ret->val);
    4178             :         } else {
    4179           0 :                 RETVAL_FALSE;
    4180             :         }
    4181          14 :         efree((void *)convmap);
    4182             : }
    4183             : /* }}} */
    4184             : 
    4185             : /* {{{ proto string mb_encode_numericentity(string string, array convmap [, string encoding [, bool is_hex]])
    4186             :    Converts specified characters to HTML numeric entities */
    4187           3 : PHP_FUNCTION(mb_encode_numericentity)
    4188             : {
    4189           3 :         php_mb_numericentity_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    4190           3 : }
    4191             : /* }}} */
    4192             : 
    4193             : /* {{{ proto string mb_decode_numericentity(string string, array convmap [, string encoding])
    4194             :    Converts HTML numeric entities to character code */
    4195          11 : PHP_FUNCTION(mb_decode_numericentity)
    4196             : {
    4197          11 :         php_mb_numericentity_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    4198          11 : }
    4199             : /* }}} */
    4200             : /* }}} */
    4201             : 
    4202             : /* {{{ proto int mb_send_mail(string to, string subject, string message [, string additional_headers [, string additional_parameters]])
    4203             :  *  Sends an email message with MIME scheme
    4204             :  */
    4205             : 
    4206             : #define SKIP_LONG_HEADER_SEP_MBSTRING(str, pos)                                                                         \
    4207             :         if (str[pos] == '\r' && str[pos + 1] == '\n' && (str[pos + 2] == ' ' || str[pos + 2] == '\t')) {        \
    4208             :                 pos += 2;                                                                                       \
    4209             :                 while (str[pos + 1] == ' ' || str[pos + 1] == '\t') {                                                   \
    4210             :                         pos++;                                                                                  \
    4211             :                 }                                                                                               \
    4212             :                 continue;                                                                                       \
    4213             :         }
    4214             : 
    4215             : #define MAIL_ASCIIZ_CHECK_MBSTRING(str, len)                    \
    4216             :         pp = str;                                       \
    4217             :         ee = pp + len;                                  \
    4218             :         while ((pp = memchr(pp, '\0', (ee - pp)))) {    \
    4219             :                 *pp = ' ';                              \
    4220             :         }                                               \
    4221             : 
    4222           1 : static int _php_mbstr_parse_mail_headers(HashTable *ht, const char *str, size_t str_len)
    4223             : {
    4224             :         const char *ps;
    4225             :         size_t icnt;
    4226           1 :         int state = 0;
    4227           1 :         int crlf_state = -1;
    4228           1 :         char *token = NULL;
    4229           1 :         size_t token_pos = 0;
    4230             :         zend_string *fld_name, *fld_val;
    4231             : 
    4232           1 :         ps = str;
    4233           1 :         icnt = str_len;
    4234           1 :         fld_name = fld_val = NULL;
    4235             : 
    4236             :         /*
    4237             :          *             C o n t e n t - T y p e :   t e x t / h t m l \r\n
    4238             :          *             ^ ^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^^^^^^^^^ ^^^^
    4239             :          *      state  0            1           2          3
    4240             :          *
    4241             :          *             C o n t e n t - T y p e :   t e x t / h t m l \r\n
    4242             :          *             ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^
    4243             :          * crlf_state -1                       0                     1 -1
    4244             :          *
    4245             :          */
    4246             : 
    4247          19 :         while (icnt > 0) {
    4248          17 :                 switch (*ps) {
    4249             :                         case ':':
    4250           1 :                                 if (crlf_state == 1) {
    4251           0 :                                         token_pos++;
    4252             :                                 }
    4253             : 
    4254           2 :                                 if (state == 0 || state == 1) {
    4255           1 :                                         if(token && token_pos > 0) {
    4256           1 :                                                 fld_name = zend_string_init(token, token_pos, 0);
    4257             :                                         }
    4258           1 :                                         state = 2;
    4259             :                                 } else {
    4260           0 :                                         token_pos++;
    4261             :                                 }
    4262             : 
    4263           1 :                                 crlf_state = 0;
    4264           1 :                                 break;
    4265             : 
    4266             :                         case '\n':
    4267           0 :                                 if (crlf_state == -1) {
    4268           0 :                                         goto out;
    4269             :                                 }
    4270           0 :                                 crlf_state = -1;
    4271           0 :                                 break;
    4272             : 
    4273             :                         case '\r':
    4274           0 :                                 if (crlf_state == 1) {
    4275           0 :                                         token_pos++;
    4276             :                                 } else {
    4277           0 :                                         crlf_state = 1;
    4278             :                                 }
    4279           0 :                                 break;
    4280             : 
    4281             :                         case ' ': case '\t':
    4282           1 :                                 if (crlf_state == -1) {
    4283           0 :                                         if (state == 3) {
    4284             :                                                 /* continuing from the previous line */
    4285           0 :                                                 state = 4;
    4286             :                                         } else {
    4287             :                                                 /* simply skipping this new line */
    4288           0 :                                                 state = 5;
    4289             :                                         }
    4290             :                                 } else {
    4291           1 :                                         if (crlf_state == 1) {
    4292           0 :                                                 token_pos++;
    4293             :                                         }
    4294           1 :                                         if (state == 1 || state == 3) {
    4295           0 :                                                 token_pos++;
    4296             :                                         }
    4297             :                                 }
    4298           1 :                                 crlf_state = 0;
    4299           1 :                                 break;
    4300             : 
    4301             :                         default:
    4302          15 :                                 switch (state) {
    4303             :                                         case 0:
    4304           1 :                                                 token = (char*)ps;
    4305           1 :                                                 token_pos = 0;
    4306           1 :                                                 state = 1;
    4307           1 :                                                 break;
    4308             : 
    4309             :                                         case 2:
    4310           1 :                                                 if (crlf_state != -1) {
    4311           1 :                                                         token = (char*)ps;
    4312           1 :                                                         token_pos = 0;
    4313             : 
    4314           1 :                                                         state = 3;
    4315           1 :                                                         break;
    4316             :                                                 }
    4317             :                                                 /* break is missing intentionally */
    4318             : 
    4319             :                                         case 3:
    4320           2 :                                                 if (crlf_state == -1) {
    4321           0 :                                                         if(token && token_pos > 0) {
    4322           0 :                                                                 fld_val = zend_string_init(token, token_pos, 0);
    4323             :                                                         }
    4324             : 
    4325           0 :                                                         if (fld_name != NULL && fld_val != NULL) {
    4326             :                                                                 zval val;
    4327             :                                                                 /* FIXME: some locale free implementation is
    4328             :                                                                  * really required here,,, */
    4329           0 :                                                                 php_strtoupper(ZSTR_VAL(fld_name), ZSTR_LEN(fld_name));
    4330           0 :                                                                 ZVAL_STR(&val, fld_val);
    4331             : 
    4332           0 :                                                                 zend_hash_update(ht, fld_name, &val);
    4333             : 
    4334             :                                                                 zend_string_release(fld_name);
    4335             :                                                         }
    4336             : 
    4337           0 :                                                         fld_name = fld_val = NULL;
    4338           0 :                                                         token = (char*)ps;
    4339           0 :                                                         token_pos = 0;
    4340             : 
    4341           0 :                                                         state = 1;
    4342             :                                                 }
    4343           2 :                                                 break;
    4344             : 
    4345             :                                         case 4:
    4346           0 :                                                 token_pos++;
    4347           0 :                                                 state = 3;
    4348             :                                                 break;
    4349             :                                 }
    4350             : 
    4351          15 :                                 if (crlf_state == 1) {
    4352           0 :                                         token_pos++;
    4353             :                                 }
    4354             : 
    4355          15 :                                 token_pos++;
    4356             : 
    4357          15 :                                 crlf_state = 0;
    4358             :                                 break;
    4359             :                 }
    4360          17 :                 ps++, icnt--;
    4361             :         }
    4362             : out:
    4363           1 :         if (state == 2) {
    4364           0 :                 token = "";
    4365           0 :                 token_pos = 0;
    4366             : 
    4367           0 :                 state = 3;
    4368             :         }
    4369           1 :         if (state == 3) {
    4370           1 :                 if(token && token_pos > 0) {
    4371           1 :                         fld_val = zend_string_init(token, token_pos, 0);
    4372             :                 }
    4373           1 :                 if (fld_name != NULL && fld_val != NULL) {
    4374             :                         zval val;
    4375             :                         /* FIXME: some locale free implementation is
    4376             :                          * really required here,,, */
    4377           1 :                         php_strtoupper(ZSTR_VAL(fld_name), ZSTR_LEN(fld_name));
    4378           1 :                         ZVAL_STR(&val, fld_val);
    4379             : 
    4380           1 :                         zend_hash_update(ht, fld_name, &val);
    4381             : 
    4382             :                         zend_string_release(fld_name);
    4383             :                 }
    4384             :         }
    4385           1 :         return state;
    4386             : }
    4387             : 
    4388          15 : PHP_FUNCTION(mb_send_mail)
    4389             : {
    4390             :         int n;
    4391          15 :         char *to = NULL;
    4392             :         size_t to_len;
    4393          15 :         char *message = NULL;
    4394             :         size_t message_len;
    4395          15 :         char *subject = NULL;
    4396             :         size_t subject_len;
    4397          15 :         zval *headers = NULL;
    4398          15 :         zend_string *extra_cmd = NULL;
    4399          15 :         zend_string *str_headers=NULL, *tmp_headers;
    4400             :         int i;
    4401          15 :         char *to_r = NULL;
    4402          15 :         char *force_extra_parameters = INI_STR("mail.force_extra_parameters");
    4403             :         struct {
    4404             :                 int cnt_type:1;
    4405             :                 int cnt_trans_enc:1;
    4406          15 :         } suppressed_hdrs = { 0, 0 };
    4407             : 
    4408          15 :         char *message_buf = NULL, *subject_buf = NULL, *p;
    4409             :         mbfl_string orig_str, conv_str;
    4410             :         mbfl_string *pstr;      /* pointer to mbfl string for return value */
    4411             :         enum mbfl_no_encoding
    4412             :                 tran_cs,        /* transfar text charset */
    4413             :                 head_enc,       /* header transfar encoding */
    4414             :                 body_enc;       /* body transfar encoding */
    4415             :         mbfl_memory_device device;      /* automatic allocateable buffer for additional header */
    4416             :         const mbfl_language *lang;
    4417          15 :         int err = 0;
    4418             :         HashTable ht_headers;
    4419             :         zval *s;
    4420             :         extern void mbfl_memory_device_unput(mbfl_memory_device *device);
    4421             :         char *pp, *ee;
    4422             : 
    4423             :         /* initialize */
    4424          15 :         mbfl_memory_device_init(&device, 0, 0);
    4425          15 :         mbfl_string_init(&orig_str);
    4426          15 :         mbfl_string_init(&conv_str);
    4427             : 
    4428             :         /* character-set, transfer-encoding */
    4429          15 :         tran_cs = mbfl_no_encoding_utf8;
    4430          15 :         head_enc = mbfl_no_encoding_base64;
    4431          15 :         body_enc = mbfl_no_encoding_base64;
    4432          15 :         lang = mbfl_no2language(MBSTRG(language));
    4433          15 :         if (lang != NULL) {
    4434          15 :                 tran_cs = lang->mail_charset;
    4435          15 :                 head_enc = lang->mail_header_encoding;
    4436          15 :                 body_enc = lang->mail_body_encoding;
    4437             :         }
    4438             : 
    4439          15 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss|zS", &to, &to_len, &subject, &subject_len, &message, &message_len, &headers, &extra_cmd) == FAILURE) {
    4440           0 :                 return;
    4441             :         }
    4442             : 
    4443             :         /* ASCIIZ check */
    4444          15 :         MAIL_ASCIIZ_CHECK_MBSTRING(to, to_len);
    4445          15 :         MAIL_ASCIIZ_CHECK_MBSTRING(subject, subject_len);
    4446          15 :         MAIL_ASCIIZ_CHECK_MBSTRING(message, message_len);
    4447          15 :         if (headers) {
    4448           2 :                 switch(Z_TYPE_P(headers)) {
    4449             :                         case IS_STRING:
    4450           2 :                                 tmp_headers = zend_string_init(Z_STRVAL_P(headers), Z_STRLEN_P(headers), 0);
    4451           1 :                                 MAIL_ASCIIZ_CHECK_MBSTRING(ZSTR_VAL(tmp_headers), ZSTR_LEN(tmp_headers));
    4452           1 :                                 str_headers = php_trim(tmp_headers, NULL, 0, 2);
    4453             :                                 zend_string_release(tmp_headers);
    4454           1 :                                 break;
    4455             :                         case IS_ARRAY:
    4456           0 :                                 str_headers = php_mail_build_headers(headers);
    4457           0 :                                 break;
    4458             :                         default:
    4459           0 :                                 php_error_docref(NULL, E_WARNING, "headers parameter must be string or array");
    4460           0 :                                 RETURN_FALSE;
    4461             :                 }
    4462             :         }
    4463          15 :         if (extra_cmd) {
    4464           0 :                 MAIL_ASCIIZ_CHECK_MBSTRING(ZSTR_VAL(extra_cmd), ZSTR_LEN(extra_cmd));
    4465             :         }
    4466             : 
    4467          15 :         zend_hash_init(&ht_headers, 0, NULL, ZVAL_PTR_DTOR, 0);
    4468             : 
    4469          15 :         if (str_headers != NULL) {
    4470           1 :                 _php_mbstr_parse_mail_headers(&ht_headers, ZSTR_VAL(str_headers), ZSTR_LEN(str_headers));
    4471             :         }
    4472             : 
    4473          15 :         if ((s = zend_hash_str_find(&ht_headers, "CONTENT-TYPE", sizeof("CONTENT-TYPE") - 1))) {
    4474             :                 char *tmp;
    4475             :                 char *param_name;
    4476           0 :                 char *charset = NULL;
    4477             : 
    4478             :                 ZEND_ASSERT(Z_TYPE_P(s) == IS_STRING);
    4479           0 :                 p = strchr(Z_STRVAL_P(s), ';');
    4480             : 
    4481           0 :                 if (p != NULL) {
    4482             :                         /* skipping the padded spaces */
    4483             :                         do {
    4484           0 :                                 ++p;
    4485           0 :                         } while (*p == ' ' || *p == '\t');
    4486             : 
    4487           0 :                         if (*p != '\0') {
    4488           0 :                                 if ((param_name = php_strtok_r(p, "= ", &tmp)) != NULL) {
    4489           0 :                                         if (strcasecmp(param_name, "charset") == 0) {
    4490           0 :                                                 enum mbfl_no_encoding _tran_cs = tran_cs;
    4491             : 
    4492           0 :                                                 charset = php_strtok_r(NULL, "= \"", &tmp);
    4493           0 :                                                 if (charset != NULL) {
    4494           0 :                                                         _tran_cs = mbfl_name2no_encoding(charset);
    4495             :                                                 }
    4496             : 
    4497           0 :                                                 if (_tran_cs == mbfl_no_encoding_invalid) {
    4498           0 :                                                         php_error_docref(NULL, E_WARNING, "Unsupported charset \"%s\" - will be regarded as ascii", charset);
    4499           0 :                                                         _tran_cs = mbfl_no_encoding_ascii;
    4500             :                                                 }
    4501           0 :                                                 tran_cs = _tran_cs;
    4502             :                                         }
    4503             :                                 }
    4504             :                         }
    4505             :                 }
    4506           0 :                 suppressed_hdrs.cnt_type = 1;
    4507             :         }
    4508             : 
    4509          15 :         if ((s = zend_hash_str_find(&ht_headers, "CONTENT-TRANSFER-ENCODING", sizeof("CONTENT-TRANSFER-ENCODING") - 1))) {
    4510             :                 enum mbfl_no_encoding _body_enc;
    4511             : 
    4512             :                 ZEND_ASSERT(Z_TYPE_P(s) == IS_STRING);
    4513           0 :                 _body_enc = mbfl_name2no_encoding(Z_STRVAL_P(s));
    4514           0 :                 switch (_body_enc) {
    4515             :                         case mbfl_no_encoding_base64:
    4516             :                         case mbfl_no_encoding_7bit:
    4517             :                         case mbfl_no_encoding_8bit:
    4518           0 :                                 body_enc = _body_enc;
    4519           0 :                                 break;
    4520             : 
    4521             :                         default:
    4522           0 :                                 php_error_docref(NULL, E_WARNING, "Unsupported transfer encoding \"%s\" - will be regarded as 8bit", Z_STRVAL_P(s));
    4523           0 :                                 body_enc =      mbfl_no_encoding_8bit;
    4524             :                                 break;
    4525             :                 }
    4526           0 :                 suppressed_hdrs.cnt_trans_enc = 1;
    4527             :         }
    4528             : 
    4529             :         /* To: */
    4530          15 :         if (to != NULL) {
    4531          15 :                 if (to_len > 0) {
    4532          15 :                         to_r = estrndup(to, to_len);
    4533          15 :                         for (; to_len; to_len--) {
    4534          15 :                                 if (!isspace((unsigned char) to_r[to_len - 1])) {
    4535          15 :                                         break;
    4536             :                                 }
    4537           0 :                                 to_r[to_len - 1] = '\0';
    4538             :                         }
    4539         300 :                         for (i = 0; to_r[i]; i++) {
    4540         285 :                         if (iscntrl((unsigned char) to_r[i])) {
    4541             :                                 /* According to RFC 822, section 3.1.1 long headers may be separated into
    4542             :                                  * parts using CRLF followed at least one linear-white-space character ('\t' or ' ').
    4543             :                                  * To prevent these separators from being replaced with a space, we use the
    4544             :                                  * SKIP_LONG_HEADER_SEP_MBSTRING to skip over them.
    4545             :                                  */
    4546           0 :                                 SKIP_LONG_HEADER_SEP_MBSTRING(to_r, i);
    4547           0 :                                 to_r[i] = ' ';
    4548             :                         }
    4549             :                         }
    4550             :                 } else {
    4551           0 :                         to_r = to;
    4552             :                 }
    4553             :         } else {
    4554           0 :                 php_error_docref(NULL, E_WARNING, "Missing To: field");
    4555           0 :                 err = 1;
    4556             :         }
    4557             : 
    4558             :         /* Subject: */
    4559          15 :         if (subject != NULL) {
    4560          15 :                 orig_str.no_language = MBSTRG(language);
    4561          15 :                 orig_str.val = (unsigned char *)subject;
    4562          15 :                 orig_str.len = subject_len;
    4563          15 :                 orig_str.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    4564          15 :                 if (orig_str.no_encoding == mbfl_no_encoding_invalid || orig_str.no_encoding == mbfl_no_encoding_pass) {
    4565           1 :                         const mbfl_encoding *encoding = mbfl_identify_encoding2(&orig_str, MBSTRG(current_detect_order_list), MBSTRG(current_detect_order_list_size), MBSTRG(strict_detection));
    4566           1 :                         orig_str.no_encoding = encoding ? encoding->no_encoding: mbfl_no_encoding_invalid;
    4567             :                 }
    4568          15 :                 pstr = mbfl_mime_header_encode(&orig_str, &conv_str, tran_cs, head_enc, "\n", sizeof("Subject: [PHP-jp nnnnnnnn]"));
    4569          15 :                 if (pstr != NULL) {
    4570          15 :                         subject_buf = subject = (char *)pstr->val;
    4571             :                 }
    4572             :         } else {
    4573           0 :                 php_error_docref(NULL, E_WARNING, "Missing Subject: field");
    4574           0 :                 err = 1;
    4575             :         }
    4576             : 
    4577             :         /* message body */
    4578          15 :         if (message != NULL) {
    4579          15 :                 orig_str.no_language = MBSTRG(language);
    4580          15 :                 orig_str.val = (unsigned char *)message;
    4581          15 :                 orig_str.len = (unsigned int)message_len;
    4582          15 :                 orig_str.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    4583             : 
    4584          15 :                 if (orig_str.no_encoding == mbfl_no_encoding_invalid || orig_str.no_encoding == mbfl_no_encoding_pass) {
    4585           1 :                         const mbfl_encoding *encoding = mbfl_identify_encoding2(&orig_str, MBSTRG(current_detect_order_list), MBSTRG(current_detect_order_list_size), MBSTRG(strict_detection));
    4586           1 :                         orig_str.no_encoding = encoding ? encoding->no_encoding: mbfl_no_encoding_invalid;
    4587             :                 }
    4588             : 
    4589          15 :                 pstr = NULL;
    4590             :                 {
    4591             :                         mbfl_string tmpstr;
    4592             : 
    4593          15 :                         if (mbfl_convert_encoding(&orig_str, &tmpstr, tran_cs) != NULL) {
    4594          15 :                                 tmpstr.no_encoding=mbfl_no_encoding_8bit;
    4595          15 :                                 pstr = mbfl_convert_encoding(&tmpstr, &conv_str, body_enc);
    4596          15 :                                 efree(tmpstr.val);
    4597             :                         }
    4598             :                 }
    4599          15 :                 if (pstr != NULL) {
    4600          15 :                         message_buf = message = (char *)pstr->val;
    4601             :                 }
    4602             :         } else {
    4603             :                 /* this is not really an error, so it is allowed. */
    4604           0 :                 php_error_docref(NULL, E_WARNING, "Empty message body");
    4605           0 :                 message = NULL;
    4606             :         }
    4607             : 
    4608             :         /* other headers */
    4609             : #define PHP_MBSTR_MAIL_MIME_HEADER1 "MIME-Version: 1.0"
    4610             : #define PHP_MBSTR_MAIL_MIME_HEADER2 "Content-Type: text/plain"
    4611             : #define PHP_MBSTR_MAIL_MIME_HEADER3 "; charset="
    4612             : #define PHP_MBSTR_MAIL_MIME_HEADER4 "Content-Transfer-Encoding: "
    4613          15 :         if (str_headers != NULL) {
    4614           1 :                 p = ZSTR_VAL(str_headers);
    4615           1 :                 n = ZSTR_LEN(str_headers);
    4616           1 :                 mbfl_memory_device_strncat(&device, p, n);
    4617             :                 zend_string_release(str_headers);
    4618           1 :                 if (n > 0 && p[n - 1] != '\n') {
    4619           1 :                         mbfl_memory_device_strncat(&device, "\n", 1);
    4620             :                 }
    4621             :         }
    4622             : 
    4623          15 :         if (!zend_hash_str_exists(&ht_headers, "MIME-VERSION", sizeof("MIME-VERSION") - 1)) {
    4624          14 :                 mbfl_memory_device_strncat(&device, PHP_MBSTR_MAIL_MIME_HEADER1, sizeof(PHP_MBSTR_MAIL_MIME_HEADER1) - 1);
    4625          14 :                 mbfl_memory_device_strncat(&device, "\n", 1);
    4626             :         }
    4627             : 
    4628          15 :         if (!suppressed_hdrs.cnt_type) {
    4629          15 :                 mbfl_memory_device_strncat(&device, PHP_MBSTR_MAIL_MIME_HEADER2, sizeof(PHP_MBSTR_MAIL_MIME_HEADER2) - 1);
    4630             : 
    4631          15 :                 p = (char *)mbfl_no2preferred_mime_name(tran_cs);
    4632          15 :                 if (p != NULL) {
    4633          15 :                         mbfl_memory_device_strncat(&device, PHP_MBSTR_MAIL_MIME_HEADER3, sizeof(PHP_MBSTR_MAIL_MIME_HEADER3) - 1);
    4634          15 :                         mbfl_memory_device_strcat(&device, p);
    4635             :                 }
    4636          15 :                 mbfl_memory_device_strncat(&device, "\n", 1);
    4637             :         }
    4638          15 :         if (!suppressed_hdrs.cnt_trans_enc) {
    4639          15 :                 mbfl_memory_device_strncat(&device, PHP_MBSTR_MAIL_MIME_HEADER4, sizeof(PHP_MBSTR_MAIL_MIME_HEADER4) - 1);
    4640          15 :                 p = (char *)mbfl_no2preferred_mime_name(body_enc);
    4641          15 :                 if (p == NULL) {
    4642           0 :                         p = "7bit";
    4643             :                 }
    4644          15 :                 mbfl_memory_device_strcat(&device, p);
    4645          15 :                 mbfl_memory_device_strncat(&device, "\n", 1);
    4646             :         }
    4647             : 
    4648          15 :         mbfl_memory_device_unput(&device);
    4649          15 :         mbfl_memory_device_output('\0', &device);
    4650          30 :         str_headers = zend_string_init((char *)device.buffer, strlen((char *)device.buffer), 0);
    4651             : 
    4652          15 :         if (force_extra_parameters) {
    4653           0 :                 extra_cmd = php_escape_shell_cmd(force_extra_parameters);
    4654          15 :         } else if (extra_cmd) {
    4655           0 :                 extra_cmd = php_escape_shell_cmd(ZSTR_VAL(extra_cmd));
    4656             :         }
    4657             : 
    4658          30 :         if (!err && php_mail(to_r, subject, message, ZSTR_VAL(str_headers), extra_cmd ? ZSTR_VAL(extra_cmd) : NULL)) {
    4659          15 :                 RETVAL_TRUE;
    4660             :         } else {
    4661           0 :                 RETVAL_FALSE;
    4662             :         }
    4663             : 
    4664          15 :         if (extra_cmd) {
    4665           0 :                 zend_string_release(extra_cmd);
    4666             :         }
    4667             : 
    4668          15 :         if (to_r != to) {
    4669          15 :                 efree(to_r);
    4670             :         }
    4671          15 :         if (subject_buf) {
    4672          15 :                 efree((void *)subject_buf);
    4673             :         }
    4674          15 :         if (message_buf) {
    4675          15 :                 efree((void *)message_buf);
    4676             :         }
    4677          15 :         mbfl_memory_device_clear(&device);
    4678          15 :         zend_hash_destroy(&ht_headers);
    4679          15 :         if (str_headers) {
    4680             :                 zend_string_release(str_headers);
    4681             :         }
    4682             : }
    4683             : 
    4684             : #undef SKIP_LONG_HEADER_SEP_MBSTRING
    4685             : #undef MAIL_ASCIIZ_CHECK_MBSTRING
    4686             : #undef PHP_MBSTR_MAIL_MIME_HEADER1
    4687             : #undef PHP_MBSTR_MAIL_MIME_HEADER2
    4688             : #undef PHP_MBSTR_MAIL_MIME_HEADER3
    4689             : #undef PHP_MBSTR_MAIL_MIME_HEADER4
    4690             : /* }}} */
    4691             : 
    4692             : /* {{{ proto mixed mb_get_info([string type])
    4693             :    Returns the current settings of mbstring */
    4694          16 : PHP_FUNCTION(mb_get_info)
    4695             : {
    4696          16 :         char *typ = NULL;
    4697             :         size_t typ_len;
    4698             :         size_t n;
    4699             :         char *name;
    4700             :         const struct mb_overload_def *over_func;
    4701             :         zval row1, row2;
    4702          16 :         const mbfl_language *lang = mbfl_no2language(MBSTRG(language));
    4703             :         const mbfl_encoding **entry;
    4704             : 
    4705          16 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &typ, &typ_len) == FAILURE) {
    4706           0 :                 return;
    4707             :         }
    4708             : 
    4709          17 :         if (!typ || !strcasecmp("all", typ)) {
    4710           1 :                 array_init(return_value);
    4711           1 :                 if (MBSTRG(current_internal_encoding)) {
    4712           1 :                         add_assoc_string(return_value, "internal_encoding", (char *)MBSTRG(current_internal_encoding)->name);
    4713             :                 }
    4714           1 :                 if (MBSTRG(http_input_identify)) {
    4715           1 :                         add_assoc_string(return_value, "http_input", (char *)MBSTRG(http_input_identify)->name);
    4716             :                 }
    4717           1 :                 if (MBSTRG(current_http_output_encoding)) {
    4718           1 :                         add_assoc_string(return_value, "http_output", (char *)MBSTRG(current_http_output_encoding)->name);
    4719             :                 }
    4720           1 :                 if ((name = (char *)zend_ini_string("mbstring.http_output_conv_mimetypes", sizeof("mbstring.http_output_conv_mimetypes") - 1, 0)) != NULL) {
    4721           1 :                         add_assoc_string(return_value, "http_output_conv_mimetypes", name);
    4722             :                 }
    4723           1 :                 add_assoc_long(return_value, "func_overload", MBSTRG(func_overload));
    4724           1 :                 if (MBSTRG(func_overload)){
    4725           1 :                         over_func = &(mb_ovld[0]);
    4726           1 :                         array_init(&row1);
    4727          15 :                         while (over_func->type > 0) {
    4728          13 :                                 if ((MBSTRG(func_overload) & over_func->type) == over_func->type ) {
    4729          12 :                                         add_assoc_string(&row1, over_func->orig_func, over_func->ovld_func);
    4730             :                                 }
    4731          13 :                                 over_func++;
    4732             :                         }
    4733           1 :                         add_assoc_zval(return_value, "func_overload_list", &row1);
    4734             :                 } else {
    4735           0 :                         add_assoc_string(return_value, "func_overload_list", "no overload");
    4736             :                 }
    4737           1 :                 if (lang != NULL) {
    4738           1 :                         if ((name = (char *)mbfl_no_encoding2name(lang->mail_charset)) != NULL) {
    4739           1 :                                 add_assoc_string(return_value, "mail_charset", name);
    4740             :                         }
    4741           1 :                         if ((name = (char *)mbfl_no_encoding2name(lang->mail_header_encoding)) != NULL) {
    4742           1 :                                 add_assoc_string(return_value, "mail_header_encoding", name);
    4743             :                         }
    4744           1 :                         if ((name = (char *)mbfl_no_encoding2name(lang->mail_body_encoding)) != NULL) {
    4745           1 :                                 add_assoc_string(return_value, "mail_body_encoding", name);
    4746             :                         }
    4747             :                 }
    4748           1 :                 add_assoc_long(return_value, "illegal_chars", MBSTRG(illegalchars));
    4749           1 :                 if (MBSTRG(encoding_translation)) {
    4750           1 :                         add_assoc_string(return_value, "encoding_translation", "On");
    4751             :                 } else {
    4752           0 :                         add_assoc_string(return_value, "encoding_translation", "Off");
    4753             :                 }
    4754           1 :                 if ((name = (char *)mbfl_no_language2name(MBSTRG(language))) != NULL) {
    4755           1 :                         add_assoc_string(return_value, "language", name);
    4756             :                 }
    4757           1 :                 n = MBSTRG(current_detect_order_list_size);
    4758           1 :                 entry = MBSTRG(current_detect_order_list);
    4759           1 :                 if (n > 0) {
    4760             :                         size_t i;
    4761           1 :                         array_init(&row2);
    4762           5 :                         for (i = 0; i < n; i++) {
    4763           4 :                                 add_next_index_string(&row2, (*entry)->name);
    4764           4 :                                 entry++;
    4765             :                         }
    4766           1 :                         add_assoc_zval(return_value, "detect_order", &row2);
    4767             :                 }
    4768           1 :                 if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE) {
    4769           0 :                         add_assoc_string(return_value, "substitute_character", "none");
    4770           1 :                 } else if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_LONG) {
    4771           0 :                         add_assoc_string(return_value, "substitute_character", "long");
    4772           1 :                 } else if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_ENTITY) {
    4773           0 :                         add_assoc_string(return_value, "substitute_character", "entity");
    4774             :                 } else {
    4775           1 :                         add_assoc_long(return_value, "substitute_character", MBSTRG(current_filter_illegal_substchar));
    4776             :                 }
    4777           1 :                 if (MBSTRG(strict_detection)) {
    4778           1 :                         add_assoc_string(return_value, "strict_detection", "On");
    4779             :                 } else {
    4780           0 :                         add_assoc_string(return_value, "strict_detection", "Off");
    4781             :                 }
    4782          15 :         } else if (!strcasecmp("internal_encoding", typ)) {
    4783           1 :                 if (MBSTRG(current_internal_encoding)) {
    4784           2 :                         RETVAL_STRING((char *)MBSTRG(current_internal_encoding)->name);
    4785             :                 }
    4786          14 :         } else if (!strcasecmp("http_input", typ)) {
    4787           1 :                 if (MBSTRG(http_input_identify)) {
    4788           2 :                         RETVAL_STRING((char *)MBSTRG(http_input_identify)->name);
    4789             :                 }
    4790          13 :         } else if (!strcasecmp("http_output", typ)) {
    4791           1 :                 if (MBSTRG(current_http_output_encoding)) {
    4792           2 :                         RETVAL_STRING((char *)MBSTRG(current_http_output_encoding)->name);
    4793             :                 }
    4794          12 :         } else if (!strcasecmp("http_output_conv_mimetypes", typ)) {
    4795           1 :                 if ((name = (char *)zend_ini_string("mbstring.http_output_conv_mimetypes", sizeof("mbstring.http_output_conv_mimetypes") - 1, 0)) != NULL) {
    4796           2 :                         RETVAL_STRING(name);
    4797             :                 }
    4798          11 :         } else if (!strcasecmp("func_overload", typ)) {
    4799           1 :                 RETVAL_LONG(MBSTRG(func_overload));
    4800          10 :         } else if (!strcasecmp("func_overload_list", typ)) {
    4801           1 :                 if (MBSTRG(func_overload)){
    4802           1 :                                 over_func = &(mb_ovld[0]);
    4803           1 :                                 array_init(return_value);
    4804          15 :                                 while (over_func->type > 0) {
    4805          13 :                                         if ((MBSTRG(func_overload) & over_func->type) == over_func->type ) {
    4806          12 :                                                 add_assoc_string(return_value, over_func->orig_func, over_func->ovld_func);
    4807             :                                         }
    4808          13 :                                         over_func++;
    4809             :                                 }
    4810             :                 } else {
    4811           0 :                         RETVAL_STRING("no overload");
    4812             :                 }
    4813           9 :         } else if (!strcasecmp("mail_charset", typ)) {
    4814           1 :                 if (lang != NULL && (name = (char *)mbfl_no_encoding2name(lang->mail_charset)) != NULL) {
    4815           2 :                         RETVAL_STRING(name);
    4816             :                 }
    4817           8 :         } else if (!strcasecmp("mail_header_encoding", typ)) {
    4818           1 :                 if (lang != NULL && (name = (char *)mbfl_no_encoding2name(lang->mail_header_encoding)) != NULL) {
    4819           2 :                         RETVAL_STRING(name);
    4820             :                 }
    4821           7 :         } else if (!strcasecmp("mail_body_encoding", typ)) {
    4822           1 :                 if (lang != NULL && (name = (char *)mbfl_no_encoding2name(lang->mail_body_encoding)) != NULL) {
    4823           2 :                         RETVAL_STRING(name);
    4824             :                 }
    4825           6 :         } else if (!strcasecmp("illegal_chars", typ)) {
    4826           1 :                 RETVAL_LONG(MBSTRG(illegalchars));
    4827           5 :         } else if (!strcasecmp("encoding_translation", typ)) {
    4828           1 :                 if (MBSTRG(encoding_translation)) {
    4829           2 :                         RETVAL_STRING("On");
    4830             :                 } else {
    4831           0 :                         RETVAL_STRING("Off");
    4832             :                 }
    4833           4 :         } else if (!strcasecmp("language", typ)) {
    4834           1 :                 if ((name = (char *)mbfl_no_language2name(MBSTRG(language))) != NULL) {
    4835           2 :                         RETVAL_STRING(name);
    4836             :                 }
    4837           3 :         } else if (!strcasecmp("detect_order", typ)) {
    4838           1 :                 n = MBSTRG(current_detect_order_list_size);
    4839           1 :                 entry = MBSTRG(current_detect_order_list);
    4840           1 :                 if (n > 0) {
    4841             :                         size_t i;
    4842           1 :                         array_init(return_value);
    4843           5 :                         for (i = 0; i < n; i++) {
    4844           4 :                                 add_next_index_string(return_value, (*entry)->name);
    4845           4 :                                 entry++;
    4846             :                         }
    4847             :                 }
    4848           2 :         } else if (!strcasecmp("substitute_character", typ)) {
    4849           1 :                 if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE) {
    4850           0 :                         RETVAL_STRING("none");
    4851           1 :                 } else if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_LONG) {
    4852           0 :                         RETVAL_STRING("long");
    4853           1 :                 } else if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_ENTITY) {
    4854           0 :                         RETVAL_STRING("entity");
    4855             :                 } else {
    4856           1 :                         RETVAL_LONG(MBSTRG(current_filter_illegal_substchar));
    4857             :                 }
    4858           1 :         } else if (!strcasecmp("strict_detection", typ)) {
    4859           1 :                 if (MBSTRG(strict_detection)) {
    4860           2 :                         RETVAL_STRING("On");
    4861             :                 } else {
    4862           0 :                         RETVAL_STRING("Off");
    4863             :                 }
    4864             :         } else {
    4865           0 :                 RETURN_FALSE;
    4866             :         }
    4867             : }
    4868             : /* }}} */
    4869             : 
    4870             : 
    4871         876 : static inline mbfl_buffer_converter *php_mb_init_convd(const mbfl_encoding *encoding)
    4872             : {
    4873             :         mbfl_buffer_converter *convd;
    4874             : 
    4875         876 :         convd = mbfl_buffer_converter_new2(encoding, encoding, 0);
    4876         876 :         if (convd == NULL) {
    4877           0 :                 return NULL;
    4878             :         }
    4879         876 :         mbfl_buffer_converter_illegal_mode(convd, MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE);
    4880         876 :         mbfl_buffer_converter_illegal_substchar(convd, 0);
    4881         876 :         return convd;
    4882             : }
    4883             : 
    4884             : 
    4885         881 : static inline int php_mb_check_encoding_impl(mbfl_buffer_converter *convd, const char *input, size_t length, const mbfl_encoding *encoding) {
    4886         881 :         mbfl_string string, result, *ret = NULL;
    4887         881 :         long illegalchars = 0;
    4888             : 
    4889             :         /* initialize string */
    4890         881 :         mbfl_string_init_set(&string, mbfl_no_language_neutral, encoding->no_encoding);
    4891         881 :         mbfl_string_init(&result);
    4892             : 
    4893         881 :         string.val = (unsigned char *) input;
    4894         881 :         string.len = length;
    4895             : 
    4896         881 :         ret = mbfl_buffer_converter_feed_result(convd, &string, &result);
    4897         881 :         illegalchars = mbfl_buffer_illegalchars(convd);
    4898             : 
    4899         881 :         if (ret != NULL) {
    4900         881 :                 if (illegalchars == 0 && string.len == result.len && memcmp(string.val, result.val, string.len) == 0) {
    4901         738 :                         mbfl_string_clear(&result);
    4902         738 :                         return 1;
    4903             :                 }
    4904         143 :                 mbfl_string_clear(&result);
    4905             :         }
    4906         143 :         return 0;
    4907             : }
    4908             : 
    4909             : 
    4910         873 : MBSTRING_API int php_mb_check_encoding(const char *input, size_t length, const char *enc)
    4911             : {
    4912         873 :         const mbfl_encoding *encoding = MBSTRG(current_internal_encoding);
    4913             :         mbfl_buffer_converter *convd;
    4914             : 
    4915         873 :         if (input == NULL) {
    4916           0 :                 return MBSTRG(illegalchars) == 0;
    4917             :         }
    4918             : 
    4919         873 :         if (enc != NULL) {
    4920         871 :                 encoding = mbfl_name2encoding(enc);
    4921         871 :                 if (!encoding || encoding == &mbfl_encoding_pass) {
    4922           0 :                         php_error_docref(NULL, E_WARNING, "Invalid encoding \"%s\"", enc);
    4923           0 :                         return 0;
    4924             :                 }
    4925             :         }
    4926             : 
    4927         873 :         convd = php_mb_init_convd(encoding);
    4928         873 :         if (convd == NULL) {
    4929           0 :                 php_error_docref(NULL, E_WARNING, "Unable to create converter");
    4930           0 :                 return 0;
    4931             :         }
    4932             : 
    4933         873 :         if (php_mb_check_encoding_impl(convd, input, length, encoding)) {
    4934         732 :                 mbfl_buffer_converter_delete(convd);
    4935         732 :                 return 1;
    4936             :         }
    4937         141 :         mbfl_buffer_converter_delete(convd);
    4938         141 :         return 0;
    4939             : }
    4940             : 
    4941             : 
    4942           3 : MBSTRING_API int php_mb_check_encoding_recursive(HashTable *vars, const zend_string *enc)
    4943             : {
    4944           3 :         const mbfl_encoding *encoding = MBSTRG(current_internal_encoding);
    4945             :         mbfl_buffer_converter *convd;
    4946             :         zend_long idx;
    4947             :         zend_string *key;
    4948             :         zval *entry;
    4949             : 
    4950             :         (void)(idx);
    4951             : 
    4952           3 :         if (enc != NULL) {
    4953           0 :                 encoding = mbfl_name2encoding(ZSTR_VAL(enc));
    4954           0 :                 if (!encoding || encoding == &mbfl_encoding_pass) {
    4955           0 :                         php_error_docref(NULL, E_WARNING, "Invalid encoding \"%s\"", ZSTR_VAL(enc));
    4956           0 :                         return 0;
    4957             :                 }
    4958             :         }
    4959             : 
    4960           3 :         convd = php_mb_init_convd(encoding);
    4961           3 :         if (convd == NULL) {
    4962           0 :                 php_error_docref(NULL, E_WARNING, "Unable to create converter");
    4963           0 :                 return 0;
    4964             :         }
    4965             : 
    4966          41 :         ZEND_HASH_FOREACH_KEY_VAL(vars, idx, key, entry) {
    4967          20 :                 ZVAL_DEREF(entry);
    4968          20 :                 if (key) {
    4969           4 :                         if (!php_mb_check_encoding_impl(convd, ZSTR_VAL(key), ZSTR_LEN(key), encoding)) {
    4970           1 :                                 mbfl_buffer_converter_delete(convd);
    4971           1 :                                 return 0;
    4972             :                         }
    4973             :                 }
    4974          19 :                 switch (Z_TYPE_P(entry)) {
    4975             :                         case IS_STRING:
    4976           4 :                                 if (!php_mb_check_encoding_impl(convd, Z_STRVAL_P(entry), Z_STRLEN_P(entry), encoding)) {
    4977           1 :                                         mbfl_buffer_converter_delete(convd);
    4978           1 :                                         return 0;
    4979             :                                 }
    4980           3 :                                 break;
    4981             :                         case IS_ARRAY:
    4982           0 :                                 if (ZEND_HASH_APPLY_PROTECTION(vars) && vars->u.v.nApplyCount++ > 0) {
    4983           0 :                                         vars->u.v.nApplyCount--;
    4984           0 :                                         php_error_docref(NULL, E_WARNING, "Cannot not handle circular references");
    4985           0 :                                         return 0;
    4986             :                                 }
    4987           0 :                                 if (!php_mb_check_encoding_recursive(HASH_OF(entry), enc)) {
    4988           0 :                                         mbfl_buffer_converter_delete(convd);
    4989           0 :                                         return 0;
    4990             :                                 }
    4991           0 :                                 break;
    4992             :                         case IS_LONG:
    4993             :                         case IS_DOUBLE:
    4994             :                         case IS_NULL:
    4995             :                         case IS_TRUE:
    4996             :                         case IS_FALSE:
    4997          15 :                                 break;
    4998             :                         default:
    4999             :                                 /* Other types are error. */
    5000           0 :                                 mbfl_buffer_converter_delete(convd);
    5001           0 :                                 return 0;
    5002             :                 }
    5003             :         } ZEND_HASH_FOREACH_END();
    5004           1 :         if (ZEND_HASH_APPLY_PROTECTION(vars)) {
    5005           1 :                 vars->u.v.nApplyCount--;
    5006             :         }
    5007             : 
    5008           1 :         mbfl_buffer_converter_delete(convd);
    5009           1 :         return 1;
    5010             : }
    5011             : 
    5012             : 
    5013             : /* {{{ proto bool mb_check_encoding([mixed var[, string encoding]])
    5014             :    Check if the string is valid for the specified encoding */
    5015         518 : PHP_FUNCTION(mb_check_encoding)
    5016             : {
    5017         518 :         zval *input = NULL;
    5018         518 :         zend_string *enc = NULL;
    5019             : 
    5020         518 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|zS", &input, &enc) == FAILURE) {
    5021           0 :                 return;
    5022             :         }
    5023             : 
    5024             :         /* FIXME: Actually check all inputs, except $_FILES file content. */
    5025         518 :         if (input == NULL) {
    5026           0 :                 if (MBSTRG(illegalchars) == 0) {
    5027           0 :                         RETURN_TRUE;
    5028             :                 }
    5029           0 :                 RETURN_FALSE;
    5030             :         }
    5031             : 
    5032        1036 :         switch(Z_TYPE_P(input)) {
    5033             :                 case IS_LONG:
    5034             :                 case IS_DOUBLE:
    5035             :                 case IS_NULL:
    5036             :                 case IS_TRUE:
    5037             :                 case IS_FALSE:
    5038           0 :                         RETURN_TRUE;
    5039             :                         break;
    5040             :                 case IS_STRING:
    5041         515 :                         if (!php_mb_check_encoding(Z_STRVAL_P(input), Z_STRLEN_P(input), enc ? ZSTR_VAL(enc): NULL)) {
    5042         138 :                                 RETURN_FALSE;
    5043             :                         }
    5044         377 :                         break;
    5045             :                 case IS_ARRAY:
    5046           6 :                         if (!php_mb_check_encoding_recursive(HASH_OF(input), enc)) {
    5047           2 :                                 RETURN_FALSE;
    5048             :                         }
    5049           1 :                         break;
    5050             :                 default:
    5051           0 :                         php_error_docref(NULL, E_WARNING, "Input is something other than scalar or array");
    5052           0 :                         RETURN_FALSE;
    5053             :         }
    5054         378 :         RETURN_TRUE;
    5055             : }
    5056             : /* }}} */
    5057             : 
    5058             : 
    5059       80007 : static inline zend_long php_mb_ord(const char* str, size_t str_len, const char* enc)
    5060             : {
    5061             :         enum mbfl_no_encoding no_enc;
    5062             :         char* ret;
    5063             :         size_t ret_len;
    5064             :         const mbfl_encoding *encoding;
    5065             :         unsigned char char_len;
    5066             :         zend_long cp;
    5067             : 
    5068       80007 :         if (enc == NULL) {
    5069       80001 :                 no_enc = MBSTRG(current_internal_encoding)->no_encoding;
    5070             :         } else {
    5071           6 :                 no_enc = mbfl_name2no_encoding(enc);
    5072             : 
    5073           6 :                 if (no_enc == mbfl_no_encoding_invalid) {
    5074           1 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", enc);
    5075           1 :                         return -1;
    5076             :                 }
    5077             :         }
    5078             : 
    5079       80006 :         if (php_mb_is_no_encoding_unicode(no_enc)) {
    5080             : 
    5081       80001 :                 ret = php_mb_convert_encoding(str, str_len, "UCS-4BE", enc, &ret_len);
    5082             : 
    5083       80001 :                 if (ret == NULL) {
    5084           0 :                         return -1;
    5085             :                 }
    5086             : 
    5087      160002 :                 cp = (unsigned char) ret[0] << 24 | \
    5088       80001 :                          (unsigned char) ret[1] << 16 | \
    5089       80001 :                          (unsigned char) ret[2] <<  8 | \
    5090       80001 :                          (unsigned char) ret[3];
    5091             : 
    5092       80001 :                 efree(ret);
    5093             : 
    5094       80001 :                 return cp;
    5095             : 
    5096           5 :         } else if (php_mb_is_unsupported_no_encoding(no_enc)) {
    5097           4 :                 php_error_docref(NULL, E_WARNING, "Unsupported encoding \"%s\"", enc);
    5098           4 :                 return -1;
    5099             :         }
    5100             : 
    5101           1 :         ret = php_mb_convert_encoding(str, str_len, enc, enc, &ret_len);
    5102             : 
    5103           1 :         if (ret == NULL) {
    5104           0 :                 return -1;
    5105             :         }
    5106             : 
    5107           1 :         encoding = mbfl_no2encoding(no_enc);
    5108           1 :         char_len = php_mb_mbchar_bytes_ex(ret, encoding);
    5109             : 
    5110           1 :         if (char_len == 1) {
    5111           0 :                 cp = (unsigned char) ret[0];
    5112           1 :         } else if (char_len == 2) {
    5113           0 :                 cp = ((unsigned char) ret[0] << 8) | \
    5114           0 :                          (unsigned char) ret[1];
    5115           1 :         } else if (char_len == 3) {
    5116           2 :                 cp = ((unsigned char) ret[0] << 16) | \
    5117           1 :                          ((unsigned char) ret[1] <<  8) | \
    5118           1 :                           (unsigned char) ret[2];
    5119             :         } else {
    5120           0 :                 cp = ((unsigned char) ret[0] << 24) | \
    5121           0 :                          ((unsigned char) ret[1] << 16) | \
    5122           0 :                          ((unsigned char) ret[2] <<  8) | \
    5123           0 :                           (unsigned char) ret[3];
    5124             :         }
    5125             : 
    5126           1 :         efree(ret);
    5127             : 
    5128           1 :         return cp;
    5129             : }
    5130             : 
    5131             : 
    5132             : /* {{{ proto bool mb_ord([string str[, string encoding]]) */
    5133       80007 : PHP_FUNCTION(mb_ord)
    5134             : {
    5135             :         char* str;
    5136             :         size_t str_len;
    5137       80007 :         char* enc = NULL;
    5138             :         size_t enc_len;
    5139             :         zend_long cp;
    5140             : 
    5141       80007 :         ZEND_PARSE_PARAMETERS_START(1, 2)
    5142      240021 :                 Z_PARAM_STRING(str, str_len)
    5143       80007 :                 Z_PARAM_OPTIONAL
    5144       80019 :                 Z_PARAM_STRING(enc, enc_len)
    5145       80007 :         ZEND_PARSE_PARAMETERS_END();
    5146             : 
    5147       80007 :         cp = php_mb_ord(str, str_len, enc);
    5148             : 
    5149       80007 :         if (0 > cp) {
    5150           5 :                 RETURN_FALSE;
    5151             :         }
    5152             : 
    5153       80002 :         RETURN_LONG(cp);
    5154             : }
    5155             : /* }}} */
    5156             : 
    5157             : 
    5158       80010 : static inline char* php_mb_chr(zend_long cp, const char* enc, size_t *output_len)
    5159             : {
    5160             :         enum mbfl_no_encoding no_enc;
    5161             :         char* buf;
    5162             :         size_t buf_len;
    5163             :         char* ret;
    5164             :         size_t ret_len;
    5165             : 
    5166       80010 :         if (enc == NULL) {
    5167       80001 :                 no_enc = MBSTRG(current_internal_encoding)->no_encoding;
    5168             :         } else {
    5169           9 :                 no_enc = mbfl_name2no_encoding(enc);
    5170           9 :                 if (no_enc == mbfl_no_encoding_invalid) {
    5171           1 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", enc);
    5172           1 :                         return NULL;
    5173             :                 }
    5174             :         }
    5175             : 
    5176       80009 :         if (php_mb_is_no_encoding_utf8(no_enc)) {
    5177             : 
    5178       80004 :                 if (0 > cp || cp > 0x10ffff || (cp > 0xd7ff && 0xe000 > cp)) {
    5179        2052 :                         if (php_mb_is_no_encoding_utf8(MBSTRG(current_internal_encoding)->no_encoding)) {
    5180        2049 :                                 cp = MBSTRG(current_filter_illegal_substchar);
    5181           3 :                         } else if (php_mb_is_no_encoding_unicode(MBSTRG(current_internal_encoding)->no_encoding)) {
    5182           3 :                                 if (0xd800 > MBSTRG(current_filter_illegal_substchar) || MBSTRG(current_filter_illegal_substchar) > 0xdfff) {
    5183           1 :                                         cp = MBSTRG(current_filter_illegal_substchar);
    5184             :                                 } else {
    5185           1 :                                         cp = 0x3f;
    5186             :                                 }
    5187             :                         } else {
    5188           1 :                                 cp = 0x3f;
    5189             :                         }
    5190             :                 }
    5191             : 
    5192       80004 :                 if (cp < 0x80) {
    5193        2178 :                         ret_len = 1;
    5194        2178 :                         ret = (char *) safe_emalloc(ret_len, 1, 1);
    5195        2178 :                         ret[0] = cp;
    5196        2178 :                         ret[1] = 0;
    5197       77826 :                 } else if (cp < 0x800) {
    5198        1920 :                         ret_len = 2;
    5199        1920 :                         ret = (char *) safe_emalloc(ret_len, 1, 1);
    5200        1920 :                         ret[0] = 0xc0 | (cp >> 6);
    5201        1920 :                         ret[1] = 0x80 | (cp & 0x3f);
    5202        1920 :                         ret[2] = 0;
    5203       75906 :                 } else if (cp < 0x10000) {
    5204       61441 :                         ret_len = 3;
    5205       61441 :                         ret = (char *) safe_emalloc(ret_len, 1, 1);
    5206       61441 :                         ret[0] = 0xe0 | (cp >> 12);
    5207       61441 :                         ret[1] = 0x80 | ((cp >> 6) & 0x3f);
    5208       61441 :                         ret[2] = 0x80 | (cp & 0x3f);
    5209       61441 :                         ret[3] = 0;
    5210             :                 } else {
    5211       14465 :                         ret_len = 4;
    5212       14465 :                         ret = (char *) safe_emalloc(ret_len, 1, 1);
    5213       14465 :                         ret[0] = 0xf0 | (cp >> 18);
    5214       14465 :                         ret[1] = 0x80 | ((cp >> 12) & 0x3f);
    5215       14465 :                         ret[2] = 0x80 | ((cp >> 6) & 0x3f);
    5216       14465 :                         ret[3] = 0x80 | (cp & 0x3f);
    5217       14465 :                         ret[4] = 0;
    5218             :                 }
    5219             : 
    5220       80004 :                 if (output_len) {
    5221       80004 :                         *output_len = ret_len;
    5222             :                 }
    5223             : 
    5224       80004 :                 return ret;
    5225             : 
    5226           5 :         } else if (php_mb_is_no_encoding_unicode(no_enc)) {
    5227             : 
    5228           0 :                 if (0 > cp || 0x10ffff < cp) {
    5229             : 
    5230           0 :                         if (php_mb_is_no_encoding_unicode(MBSTRG(current_internal_encoding)->no_encoding)) {
    5231           0 :                                 cp = MBSTRG(current_filter_illegal_substchar);
    5232             :                         } else {
    5233           0 :                                 cp = 0x3f;
    5234             :                         }
    5235             : 
    5236             :                 }
    5237             : 
    5238           0 :                 buf_len = 4;
    5239           0 :                 buf = (char *) safe_emalloc(buf_len, 1, 1);
    5240           0 :                 buf[0] = (cp >> 24) & 0xff;
    5241           0 :                 buf[1] = (cp >> 16) & 0xff;
    5242           0 :                 buf[2] = (cp >>  8) & 0xff;
    5243           0 :                 buf[3] = cp & 0xff;
    5244           0 :                 buf[4] = 0;
    5245             : 
    5246           0 :                 ret = php_mb_convert_encoding(buf, buf_len, enc, "UCS-4BE", &ret_len);
    5247           0 :                 efree(buf);
    5248             : 
    5249           0 :                 if (output_len) {
    5250           0 :                         *output_len = ret_len;
    5251             :                 }
    5252             : 
    5253           0 :                 return ret;
    5254             : 
    5255           5 :         } else if (php_mb_is_unsupported_no_encoding(no_enc)) {
    5256           4 :                 php_error_docref(NULL, E_WARNING, "Unsupported encoding \"%s\"", enc);
    5257           4 :                 return NULL;
    5258             :         }
    5259             : 
    5260           1 :         if (0 > cp || cp > 0x100000000) {
    5261           0 :                 if (no_enc == MBSTRG(current_internal_encoding)->no_encoding) {
    5262           0 :                         cp = MBSTRG(current_filter_illegal_substchar);
    5263             :                 } else {
    5264           0 :                         cp = 0x3f;
    5265             :                 }
    5266             :         }
    5267             : 
    5268           1 :         if (cp < 0x100) {
    5269           0 :                 buf_len = 1;
    5270           0 :                 buf = (char *) safe_emalloc(buf_len, 1, 1);
    5271           0 :                 buf[0] = cp;
    5272           0 :                 buf[1] = 0;
    5273           1 :         } else if (cp < 0x10000) {
    5274           0 :                 buf_len = 2;
    5275           0 :                 buf = (char *) safe_emalloc(buf_len, 1, 1);
    5276           0 :                 buf[0] = cp >> 8;
    5277           0 :                 buf[1] = cp & 0xff;
    5278           0 :                 buf[2] = 0;
    5279           1 :         } else if (cp < 0x1000000) {
    5280           1 :                 buf_len = 3;
    5281           1 :                 buf = (char *) safe_emalloc(buf_len, 1, 1);
    5282           1 :                 buf[0] = cp >> 16;
    5283           1 :                 buf[1] = (cp >> 8) & 0xff;
    5284           1 :                 buf[2] = cp & 0xff;
    5285           1 :                 buf[3] = 0;
    5286             :         } else {
    5287           0 :                 buf_len = 4;
    5288           0 :                 buf = (char *) safe_emalloc(buf_len, 1, 1);
    5289           0 :                 buf[0] = cp >> 24;
    5290           0 :                 buf[1] = (cp >> 16) & 0xff;
    5291           0 :                 buf[2] = (cp >> 8) & 0xff;
    5292           0 :                 buf[3] = cp & 0xff;
    5293           0 :                 buf[4] = 0;
    5294             :         }
    5295             : 
    5296           1 :         ret = php_mb_convert_encoding(buf, buf_len, enc, enc, &ret_len);
    5297           1 :         efree(buf);
    5298             : 
    5299           1 :         if (output_len) {
    5300           1 :                 *output_len = ret_len;
    5301             :         }
    5302             : 
    5303           1 :         return ret;
    5304             : }
    5305             : 
    5306             : 
    5307             : /* {{{ proto bool mb_ord([int cp[, string encoding]]) */
    5308       80010 : PHP_FUNCTION(mb_chr)
    5309             : {
    5310             :         zend_long cp;
    5311       80010 :         char* enc = NULL;
    5312             :         size_t enc_len;
    5313             :         char* ret;
    5314             :         size_t ret_len;
    5315             : 
    5316       80010 :         ZEND_PARSE_PARAMETERS_START(1, 2)
    5317      240030 :                 Z_PARAM_LONG(cp)
    5318       80010 :                 Z_PARAM_OPTIONAL
    5319       80028 :                 Z_PARAM_STRING(enc, enc_len)
    5320       80010 :         ZEND_PARSE_PARAMETERS_END();
    5321             : 
    5322       80010 :         ret = php_mb_chr(cp, enc, &ret_len);
    5323             : 
    5324       80010 :         if (ret == NULL) {
    5325           5 :                 RETURN_FALSE;
    5326             :         }
    5327             : 
    5328      160010 :         RETVAL_STRING(ret);
    5329       80005 :         efree(ret);
    5330             : }
    5331             : /* }}} */
    5332             : 
    5333             : 
    5334           2 : static inline char* php_mb_scrub(const char* str, size_t str_len, const char* enc)
    5335             : {
    5336             :         size_t ret_len;
    5337             : 
    5338           2 :         return php_mb_convert_encoding(str, str_len, enc, enc, &ret_len);
    5339             : }
    5340             : 
    5341             : 
    5342             : /* {{{ proto bool mb_scrub([string str[, string encoding]]) */
    5343           2 : PHP_FUNCTION(mb_scrub)
    5344             : {
    5345             :         char* str;
    5346             :         size_t str_len;
    5347           2 :         char *enc = NULL;
    5348             :         size_t enc_len;
    5349             :         char *ret;
    5350             : 
    5351           2 :         ZEND_PARSE_PARAMETERS_START(1, 2)
    5352           6 :                 Z_PARAM_STRING(str, str_len)
    5353           2 :                 Z_PARAM_OPTIONAL
    5354           4 :                 Z_PARAM_STRING(enc, enc_len)
    5355           2 :         ZEND_PARSE_PARAMETERS_END();
    5356             : 
    5357           2 :         if (enc == NULL) {
    5358           1 :                 enc = (char *) MBSTRG(current_internal_encoding)->name;
    5359           1 :         } else if (!mbfl_is_support_encoding(enc)) {
    5360           0 :                 php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", enc);
    5361           0 :                 RETURN_FALSE;
    5362             :         }
    5363             : 
    5364           2 :         ret = php_mb_scrub(str, str_len, enc);
    5365             : 
    5366           2 :         if (ret == NULL) {
    5367           0 :                 RETURN_FALSE;
    5368             :         }
    5369             : 
    5370           4 :         RETVAL_STRING(ret);
    5371           2 :         efree(ret);
    5372             : }
    5373             : /* }}} */
    5374             : 
    5375             : 
    5376             : /* {{{ php_mb_populate_current_detect_order_list */
    5377       23904 : static void php_mb_populate_current_detect_order_list(void)
    5378             : {
    5379       23904 :         const mbfl_encoding **entry = 0;
    5380             :         size_t nentries;
    5381             : 
    5382       23904 :         if (MBSTRG(current_detect_order_list)) {
    5383           0 :                 return;
    5384             :         }
    5385             : 
    5386       23906 :         if (MBSTRG(detect_order_list) && MBSTRG(detect_order_list_size)) {
    5387           2 :                 nentries = MBSTRG(detect_order_list_size);
    5388           2 :                 entry = (const mbfl_encoding **)safe_emalloc(nentries, sizeof(mbfl_encoding*), 0);
    5389           2 :                 memcpy(entry, MBSTRG(detect_order_list), sizeof(mbfl_encoding*) * nentries);
    5390             :         } else {
    5391       23902 :                 const enum mbfl_no_encoding *src = MBSTRG(default_detect_order_list);
    5392             :                 size_t i;
    5393       23902 :                 nentries = MBSTRG(default_detect_order_list_size);
    5394       23902 :                 entry = (const mbfl_encoding **)safe_emalloc(nentries, sizeof(mbfl_encoding*), 0);
    5395       71748 :                 for (i = 0; i < nentries; i++) {
    5396       47846 :                         entry[i] = mbfl_no2encoding(src[i]);
    5397             :                 }
    5398             :         }
    5399       23904 :         MBSTRG(current_detect_order_list) = entry;
    5400       23904 :         MBSTRG(current_detect_order_list_size) = nentries;
    5401             : }
    5402             : /* }}} */
    5403             : 
    5404             : /* {{{ static int php_mb_encoding_translation() */
    5405         221 : static int php_mb_encoding_translation(void)
    5406             : {
    5407         221 :         return MBSTRG(encoding_translation);
    5408             : }
    5409             : /* }}} */
    5410             : 
    5411             : /* {{{ MBSTRING_API size_t php_mb_mbchar_bytes_ex() */
    5412        1120 : MBSTRING_API size_t php_mb_mbchar_bytes_ex(const char *s, const mbfl_encoding *enc)
    5413             : {
    5414        1120 :         if (enc != NULL) {
    5415        1120 :                 if (enc->flag & MBFL_ENCTYPE_MBCS) {
    5416        1116 :                         if (enc->mblen_table != NULL) {
    5417        1116 :                                 if (s != NULL) return enc->mblen_table[*(unsigned char *)s];
    5418             :                         }
    5419           4 :                 } else if (enc->flag & (MBFL_ENCTYPE_WCS2BE | MBFL_ENCTYPE_WCS2LE)) {
    5420           0 :                         return 2;
    5421           4 :                 } else if (enc->flag & (MBFL_ENCTYPE_WCS4BE | MBFL_ENCTYPE_WCS4LE)) {
    5422           0 :                         return 4;
    5423             :                 }
    5424             :         }
    5425           4 :         return 1;
    5426             : }
    5427             : /* }}} */
    5428             : 
    5429             : /* {{{ MBSTRING_API size_t php_mb_mbchar_bytes() */
    5430           0 : MBSTRING_API size_t php_mb_mbchar_bytes(const char *s)
    5431             : {
    5432           0 :         return php_mb_mbchar_bytes_ex(s, MBSTRG(internal_encoding));
    5433             : }
    5434             : /* }}} */
    5435             : 
    5436             : /* {{{ MBSTRING_API char *php_mb_safe_strrchr_ex() */
    5437           2 : MBSTRING_API char *php_mb_safe_strrchr_ex(const char *s, unsigned int c, size_t nbytes, const mbfl_encoding *enc)
    5438             : {
    5439           2 :         register const char *p = s;
    5440           2 :         char *last=NULL;
    5441             : 
    5442           2 :         if (nbytes == (size_t)-1) {
    5443           0 :                 size_t nb = 0;
    5444             : 
    5445           0 :                 while (*p != '\0') {
    5446           0 :                         if (nb == 0) {
    5447           0 :                                 if ((unsigned char)*p == (unsigned char)c) {
    5448           0 :                                         last = (char *)p;
    5449             :                                 }
    5450           0 :                                 nb = php_mb_mbchar_bytes_ex(p, enc);
    5451           0 :                                 if (nb == 0) {
    5452           0 :                                         return NULL; /* something is going wrong! */
    5453             :                                 }
    5454             :                         }
    5455           0 :                         --nb;
    5456           0 :                         ++p;
    5457             :                 }
    5458             :         } else {
    5459           2 :                 register size_t bcnt = nbytes;
    5460             :                 register size_t nbytes_char;
    5461          22 :                 while (bcnt > 0) {
    5462          18 :                         if ((unsigned char)*p == (unsigned char)c) {
    5463           0 :                                 last = (char *)p;
    5464             :                         }
    5465          18 :                         nbytes_char = php_mb_mbchar_bytes_ex(p, enc);
    5466          18 :                         if (bcnt < nbytes_char) {
    5467           0 :                                 return NULL;
    5468             :                         }
    5469          18 :                         p += nbytes_char;
    5470          18 :                         bcnt -= nbytes_char;
    5471             :                 }
    5472             :         }
    5473           2 :         return last;
    5474             : }
    5475             : /* }}} */
    5476             : 
    5477             : /* {{{ MBSTRING_API char *php_mb_safe_strrchr() */
    5478           0 : MBSTRING_API char *php_mb_safe_strrchr(const char *s, unsigned int c, size_t nbytes)
    5479             : {
    5480           0 :         return php_mb_safe_strrchr_ex(s, c, nbytes, MBSTRG(internal_encoding));
    5481             : }
    5482             : /* }}} */
    5483             : 
    5484             : /* {{{ MBSTRING_API int php_mb_stripos()
    5485             :  */
    5486         625 : MBSTRING_API int php_mb_stripos(int mode, const char *old_haystack, unsigned int old_haystack_len, const char *old_needle, unsigned int old_needle_len, long offset, const char *from_encoding)
    5487             : {
    5488             :         int n;
    5489             :         mbfl_string haystack, needle;
    5490         625 :         n = -1;
    5491             : 
    5492         625 :         mbfl_string_init(&haystack);
    5493         625 :         mbfl_string_init(&needle);
    5494         625 :         haystack.no_language = MBSTRG(language);
    5495         625 :         haystack.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    5496         625 :         needle.no_language = MBSTRG(language);
    5497         625 :         needle.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    5498             : 
    5499             :         do {
    5500         625 :                 size_t len = 0;
    5501         625 :                 haystack.val = (unsigned char *)php_unicode_convert_case(PHP_UNICODE_CASE_UPPER, (char *)old_haystack, old_haystack_len, &len, from_encoding);
    5502         625 :                 haystack.len = len;
    5503             : 
    5504         625 :                 if (!haystack.val) {
    5505          40 :                         break;
    5506             :                 }
    5507             : 
    5508         585 :                 if (haystack.len <= 0) {
    5509          32 :                         break;
    5510             :                 }
    5511             : 
    5512         553 :                 needle.val = (unsigned char *)php_unicode_convert_case(PHP_UNICODE_CASE_UPPER, (char *)old_needle, old_needle_len, &len, from_encoding);
    5513         553 :                 needle.len = len;
    5514             : 
    5515         553 :                 if (!needle.val) {
    5516           0 :                         break;
    5517             :                 }
    5518             : 
    5519         553 :                 if (needle.len <= 0) {
    5520          16 :                         break;
    5521             :                 }
    5522             : 
    5523         537 :                 haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(from_encoding);
    5524         537 :                 if (haystack.no_encoding == mbfl_no_encoding_invalid) {
    5525           0 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", from_encoding);
    5526           0 :                         break;
    5527             :                 }
    5528             : 
    5529             :                 {
    5530         537 :                         int haystack_char_len = mbfl_strlen(&haystack);
    5531             : 
    5532         537 :                         if (mode) {
    5533         252 :                                 if ((offset > 0 && offset > haystack_char_len) ||
    5534           8 :                                         (offset < 0 && -offset > haystack_char_len)) {
    5535          15 :                                         php_error_docref(NULL, E_WARNING, "Offset is greater than the length of haystack string");
    5536          15 :                                         break;
    5537             :                                 }
    5538             :                         } else {
    5539         293 :                                 if (offset < 0) {
    5540          28 :                                         offset += (long)haystack_char_len;
    5541             :                                 }
    5542         293 :                                 if (offset < 0 || offset > haystack_char_len) {
    5543          26 :                                         php_error_docref(NULL, E_WARNING, "Offset not contained in string");
    5544          26 :                                         break;
    5545             :                                 }
    5546             :                         }
    5547             :                 }
    5548             : 
    5549         496 :                 n = mbfl_strpos(&haystack, &needle, offset, mode);
    5550             :         } while(0);
    5551             : 
    5552         625 :         if (haystack.val) {
    5553         585 :                 efree(haystack.val);
    5554             :         }
    5555             : 
    5556         625 :         if (needle.val) {
    5557         553 :                 efree(needle.val);
    5558             :         }
    5559             : 
    5560         625 :         return n;
    5561             : }
    5562             : /* }}} */
    5563             : 
    5564           1 : static void php_mb_gpc_get_detect_order(const zend_encoding ***list, size_t *list_size) /* {{{ */
    5565             : {
    5566           1 :         *list = (const zend_encoding **)MBSTRG(http_input_list);
    5567           1 :         *list_size = MBSTRG(http_input_list_size);
    5568           1 : }
    5569             : /* }}} */
    5570             : 
    5571           0 : static void php_mb_gpc_set_input_encoding(const zend_encoding *encoding) /* {{{ */
    5572             : {
    5573           0 :         MBSTRG(http_input_identify) = (const mbfl_encoding*)encoding;
    5574           0 : }
    5575             : /* }}} */
    5576             : 
    5577             : #endif  /* HAVE_MBSTRING */
    5578             : 
    5579             : /*
    5580             :  * Local variables:
    5581             :  * tab-width: 4
    5582             :  * c-basic-offset: 4
    5583             :  * End:
    5584             :  * vim600: fdm=marker
    5585             :  * vim: noet sw=4 ts=4
    5586             :  */

Generated by: LCOV version 1.10

Generated at Tue, 27 Sep 2016 10:25:59 +0000 (4 days ago)

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