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: 1736 2116 82.0 %
Date: 2014-09-27 Functions: 89 95 93.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Sat, 27 Sep 2014 16:43:11 +0000 (4 days ago)

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