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

Generated by: LCOV version 1.10

Generated at Fri, 31 Jul 2015 08:58:51 +0000 (2 days ago)

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