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

Generated by: LCOV version 1.10

Generated at Wed, 20 Jul 2016 02:56:20 +0000 (6 days ago)

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