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

Generated by: LCOV version 1.10

Generated at Sun, 29 Mar 2015 03:45:52 +0000 (34 hours ago)

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