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: 1738 2121 81.9 %
Date: 2016-02-09 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-2016 The PHP Group                                |
       6             :    +----------------------------------------------------------------------+
       7             :    | This source file is subject to version 3.01 of the PHP license,      |
       8             :    | that is bundled with this package in the file LICENSE, and is        |
       9             :    | available through the world-wide-web at the following url:           |
      10             :    | http://www.php.net/license/3_01.txt                                  |
      11             :    | If you did not receive a copy of the PHP license and are unable to   |
      12             :    | obtain it through the world-wide-web, please send a note to          |
      13             :    | license@php.net so we can mail you a copy immediately.               |
      14             :    +----------------------------------------------------------------------+
      15             :    | Author: Tsukada Takuya <tsukada@fminn.nagano.nagano.jp>              |
      16             :    |         Rui Hirokawa <hirokawa@php.net>                              |
      17             :    +----------------------------------------------------------------------+
      18             :  */
      19             : 
      20             : /* $Id$ */
      21             : 
      22             : /*
      23             :  * PHP 4 Multibyte String module "mbstring"
      24             :  *
      25             :  * History:
      26             :  *   2000.5.19  Release php-4.0RC2_jstring-1.0
      27             :  *   2001.4.1   Release php4_jstring-1.0.91
      28             :  *   2001.4.30  Release php4_jstring-1.1 (contribute to The PHP Group)
      29             :  *   2001.5.1   Renamed from jstring to mbstring (hirokawa@php.net)
      30             :  */
      31             : 
      32             : /*
      33             :  * PHP3 Internationalization support program.
      34             :  *
      35             :  * Copyright (c) 1999,2000 by the PHP3 internationalization team.
      36             :  * All rights reserved.
      37             :  *
      38             :  * See README_PHP3-i18n-ja for more detail.
      39             :  *
      40             :  * Authors:
      41             :  *    Hironori Sato <satoh@jpnnet.com>
      42             :  *    Shigeru Kanemoto <sgk@happysize.co.jp>
      43             :  *    Tsukada Takuya <tsukada@fminn.nagano.nagano.jp>
      44             :  *    Rui Hirokawa <rui_hirokawa@ybb.ne.jp>
      45             :  */
      46             : 
      47             : /* {{{ includes */
      48             : #ifdef HAVE_CONFIG_H
      49             : #include "config.h"
      50             : #endif
      51             : 
      52             : #include "php.h"
      53             : #include "php_ini.h"
      54             : #include "php_variables.h"
      55             : #include "mbstring.h"
      56             : #include "ext/standard/php_string.h"
      57             : #include "ext/standard/php_mail.h"
      58             : #include "ext/standard/exec.h"
      59             : #include "ext/standard/url.h"
      60             : #include "main/php_output.h"
      61             : #include "ext/standard/info.h"
      62             : 
      63             : #include "libmbfl/mbfl/mbfl_allocators.h"
      64             : #include "libmbfl/mbfl/mbfilter_pass.h"
      65             : 
      66             : #include "php_variables.h"
      67             : #include "php_globals.h"
      68             : #include "rfc1867.h"
      69             : #include "php_content_types.h"
      70             : #include "SAPI.h"
      71             : #include "php_unicode.h"
      72             : #include "TSRM.h"
      73             : 
      74             : #include "mb_gpc.h"
      75             : 
      76             : #if HAVE_MBREGEX
      77             : #include "php_mbregex.h"
      78             : #endif
      79             : 
      80             : #include "zend_multibyte.h"
      81             : 
      82             : #if HAVE_ONIG
      83             : #include "php_onig_compat.h"
      84             : #include <oniguruma.h>
      85             : #undef UChar
      86             : #elif HAVE_PCRE || HAVE_BUNDLED_PCRE
      87             : #include "ext/pcre/php_pcre.h"
      88             : #endif
      89             : /* }}} */
      90             : 
      91             : #if HAVE_MBSTRING
      92             : 
      93             : /* {{{ prototypes */
      94             : ZEND_DECLARE_MODULE_GLOBALS(mbstring)
      95             : 
      96             : static PHP_GINIT_FUNCTION(mbstring);
      97             : static PHP_GSHUTDOWN_FUNCTION(mbstring);
      98             : 
      99             : static void php_mb_populate_current_detect_order_list(void);
     100             : 
     101             : static int php_mb_encoding_translation(void);
     102             : 
     103             : static void php_mb_gpc_get_detect_order(const zend_encoding ***list, size_t *list_size);
     104             : 
     105             : static void php_mb_gpc_set_input_encoding(const zend_encoding *encoding);
     106             : 
     107             : /* }}} */
     108             : 
     109             : /* {{{ php_mb_default_identify_list */
     110             : typedef struct _php_mb_nls_ident_list {
     111             :         enum mbfl_no_language lang;
     112             :         const enum mbfl_no_encoding *list;
     113             :         size_t list_size;
     114             : } php_mb_nls_ident_list;
     115             : 
     116             : static const enum mbfl_no_encoding php_mb_default_identify_list_ja[] = {
     117             :         mbfl_no_encoding_ascii,
     118             :         mbfl_no_encoding_jis,
     119             :         mbfl_no_encoding_utf8,
     120             :         mbfl_no_encoding_euc_jp,
     121             :         mbfl_no_encoding_sjis
     122             : };
     123             : 
     124             : static const enum mbfl_no_encoding php_mb_default_identify_list_cn[] = {
     125             :         mbfl_no_encoding_ascii,
     126             :         mbfl_no_encoding_utf8,
     127             :         mbfl_no_encoding_euc_cn,
     128             :         mbfl_no_encoding_cp936
     129             : };
     130             : 
     131             : static const enum mbfl_no_encoding php_mb_default_identify_list_tw_hk[] = {
     132             :         mbfl_no_encoding_ascii,
     133             :         mbfl_no_encoding_utf8,
     134             :         mbfl_no_encoding_euc_tw,
     135             :         mbfl_no_encoding_big5
     136             : };
     137             : 
     138             : static const enum mbfl_no_encoding php_mb_default_identify_list_kr[] = {
     139             :         mbfl_no_encoding_ascii,
     140             :         mbfl_no_encoding_utf8,
     141             :         mbfl_no_encoding_euc_kr,
     142             :         mbfl_no_encoding_uhc
     143             : };
     144             : 
     145             : static const enum mbfl_no_encoding php_mb_default_identify_list_ru[] = {
     146             :         mbfl_no_encoding_ascii,
     147             :         mbfl_no_encoding_utf8,
     148             :         mbfl_no_encoding_koi8r,
     149             :         mbfl_no_encoding_cp1251,
     150             :         mbfl_no_encoding_cp866
     151             : };
     152             : 
     153             : static const enum mbfl_no_encoding php_mb_default_identify_list_hy[] = {
     154             :         mbfl_no_encoding_ascii,
     155             :         mbfl_no_encoding_utf8,
     156             :         mbfl_no_encoding_armscii8
     157             : };
     158             : 
     159             : static const enum mbfl_no_encoding php_mb_default_identify_list_tr[] = {
     160             :         mbfl_no_encoding_ascii,
     161             :         mbfl_no_encoding_utf8,
     162             :         mbfl_no_encoding_cp1254,
     163             :         mbfl_no_encoding_8859_9
     164             : };
     165             : 
     166             : static const enum mbfl_no_encoding php_mb_default_identify_list_ua[] = {
     167             :         mbfl_no_encoding_ascii,
     168             :         mbfl_no_encoding_utf8,
     169             :         mbfl_no_encoding_koi8u
     170             : };
     171             : 
     172             : static const enum mbfl_no_encoding php_mb_default_identify_list_neut[] = {
     173             :         mbfl_no_encoding_ascii,
     174             :         mbfl_no_encoding_utf8
     175             : };
     176             : 
     177             : 
     178             : static const php_mb_nls_ident_list php_mb_default_identify_list[] = {
     179             :         { mbfl_no_language_japanese, php_mb_default_identify_list_ja, sizeof(php_mb_default_identify_list_ja) / sizeof(php_mb_default_identify_list_ja[0]) },
     180             :         { mbfl_no_language_korean, php_mb_default_identify_list_kr, sizeof(php_mb_default_identify_list_kr) / sizeof(php_mb_default_identify_list_kr[0]) },
     181             :         { mbfl_no_language_traditional_chinese, php_mb_default_identify_list_tw_hk, sizeof(php_mb_default_identify_list_tw_hk) / sizeof(php_mb_default_identify_list_tw_hk[0]) },
     182             :         { mbfl_no_language_simplified_chinese, php_mb_default_identify_list_cn, sizeof(php_mb_default_identify_list_cn) / sizeof(php_mb_default_identify_list_cn[0]) },
     183             :         { mbfl_no_language_russian, php_mb_default_identify_list_ru, sizeof(php_mb_default_identify_list_ru) / sizeof(php_mb_default_identify_list_ru[0]) },
     184             :         { mbfl_no_language_armenian, php_mb_default_identify_list_hy, sizeof(php_mb_default_identify_list_hy) / sizeof(php_mb_default_identify_list_hy[0]) },
     185             :         { mbfl_no_language_turkish, php_mb_default_identify_list_tr, sizeof(php_mb_default_identify_list_tr) / sizeof(php_mb_default_identify_list_tr[0]) },
     186             :         { mbfl_no_language_ukrainian, php_mb_default_identify_list_ua, sizeof(php_mb_default_identify_list_ua) / sizeof(php_mb_default_identify_list_ua[0]) },
     187             :         { mbfl_no_language_neutral, php_mb_default_identify_list_neut, sizeof(php_mb_default_identify_list_neut) / sizeof(php_mb_default_identify_list_neut[0]) }
     188             : };
     189             : 
     190             : /* }}} */
     191             : 
     192             : /* {{{ mb_overload_def mb_ovld[] */
     193             : static const struct mb_overload_def mb_ovld[] = {
     194             :         {MB_OVERLOAD_MAIL, "mail", "mb_send_mail", "mb_orig_mail"},
     195             :         {MB_OVERLOAD_STRING, "strlen", "mb_strlen", "mb_orig_strlen"},
     196             :         {MB_OVERLOAD_STRING, "strpos", "mb_strpos", "mb_orig_strpos"},
     197             :         {MB_OVERLOAD_STRING, "strrpos", "mb_strrpos", "mb_orig_strrpos"},
     198             :         {MB_OVERLOAD_STRING, "stripos", "mb_stripos", "mb_orig_stripos"},
     199             :         {MB_OVERLOAD_STRING, "strripos", "mb_strripos", "mb_orig_strripos"},
     200             :         {MB_OVERLOAD_STRING, "strstr", "mb_strstr", "mb_orig_strstr"},
     201             :         {MB_OVERLOAD_STRING, "strrchr", "mb_strrchr", "mb_orig_strrchr"},
     202             :         {MB_OVERLOAD_STRING, "stristr", "mb_stristr", "mb_orig_stristr"},
     203             :         {MB_OVERLOAD_STRING, "substr", "mb_substr", "mb_orig_substr"},
     204             :         {MB_OVERLOAD_STRING, "strtolower", "mb_strtolower", "mb_orig_strtolower"},
     205             :         {MB_OVERLOAD_STRING, "strtoupper", "mb_strtoupper", "mb_orig_strtoupper"},
     206             :         {MB_OVERLOAD_STRING, "substr_count", "mb_substr_count", "mb_orig_substr_count"},
     207             :         {0, NULL, NULL, NULL}
     208             : };
     209             : /* }}} */
     210             : 
     211             : /* {{{ arginfo */
     212             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_language, 0, 0, 0)
     213             :         ZEND_ARG_INFO(0, language)
     214             : ZEND_END_ARG_INFO()
     215             : 
     216             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_internal_encoding, 0, 0, 0)
     217             :         ZEND_ARG_INFO(0, encoding)
     218             : ZEND_END_ARG_INFO()
     219             : 
     220             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_http_input, 0, 0, 0)
     221             :         ZEND_ARG_INFO(0, type)
     222             : ZEND_END_ARG_INFO()
     223             : 
     224             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_http_output, 0, 0, 0)
     225             :         ZEND_ARG_INFO(0, encoding)
     226             : ZEND_END_ARG_INFO()
     227             : 
     228             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_detect_order, 0, 0, 0)
     229             :         ZEND_ARG_INFO(0, encoding)
     230             : ZEND_END_ARG_INFO()
     231             : 
     232             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_substitute_character, 0, 0, 0)
     233             :         ZEND_ARG_INFO(0, substchar)
     234             : ZEND_END_ARG_INFO()
     235             : 
     236             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_preferred_mime_name, 0, 0, 1)
     237             :         ZEND_ARG_INFO(0, encoding)
     238             : ZEND_END_ARG_INFO()
     239             : 
     240             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_parse_str, 0, 0, 1)
     241             :         ZEND_ARG_INFO(0, encoded_string)
     242             :         ZEND_ARG_INFO(1, result)
     243             : ZEND_END_ARG_INFO()
     244             : 
     245             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_output_handler, 0, 0, 2)
     246             :         ZEND_ARG_INFO(0, contents)
     247             :         ZEND_ARG_INFO(0, status)
     248             : ZEND_END_ARG_INFO()
     249             : 
     250             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strlen, 0, 0, 1)
     251             :         ZEND_ARG_INFO(0, str)
     252             :         ZEND_ARG_INFO(0, encoding)
     253             : ZEND_END_ARG_INFO()
     254             : 
     255             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strpos, 0, 0, 2)
     256             :         ZEND_ARG_INFO(0, haystack)
     257             :         ZEND_ARG_INFO(0, needle)
     258             :         ZEND_ARG_INFO(0, offset)
     259             :         ZEND_ARG_INFO(0, encoding)
     260             : ZEND_END_ARG_INFO()
     261             : 
     262             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strrpos, 0, 0, 2)
     263             :         ZEND_ARG_INFO(0, haystack)
     264             :         ZEND_ARG_INFO(0, needle)
     265             :         ZEND_ARG_INFO(0, offset)
     266             :         ZEND_ARG_INFO(0, encoding)
     267             : ZEND_END_ARG_INFO()
     268             : 
     269             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_stripos, 0, 0, 2)
     270             :         ZEND_ARG_INFO(0, haystack)
     271             :         ZEND_ARG_INFO(0, needle)
     272             :         ZEND_ARG_INFO(0, offset)
     273             :         ZEND_ARG_INFO(0, encoding)
     274             : ZEND_END_ARG_INFO()
     275             : 
     276             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strripos, 0, 0, 2)
     277             :         ZEND_ARG_INFO(0, haystack)
     278             :         ZEND_ARG_INFO(0, needle)
     279             :         ZEND_ARG_INFO(0, offset)
     280             :         ZEND_ARG_INFO(0, encoding)
     281             : ZEND_END_ARG_INFO()
     282             : 
     283             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strstr, 0, 0, 2)
     284             :         ZEND_ARG_INFO(0, haystack)
     285             :         ZEND_ARG_INFO(0, needle)
     286             :         ZEND_ARG_INFO(0, part)
     287             :         ZEND_ARG_INFO(0, encoding)
     288             : ZEND_END_ARG_INFO()
     289             : 
     290             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strrchr, 0, 0, 2)
     291             :         ZEND_ARG_INFO(0, haystack)
     292             :         ZEND_ARG_INFO(0, needle)
     293             :         ZEND_ARG_INFO(0, part)
     294             :         ZEND_ARG_INFO(0, encoding)
     295             : ZEND_END_ARG_INFO()
     296             : 
     297             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_stristr, 0, 0, 2)
     298             :         ZEND_ARG_INFO(0, haystack)
     299             :         ZEND_ARG_INFO(0, needle)
     300             :         ZEND_ARG_INFO(0, part)
     301             :         ZEND_ARG_INFO(0, encoding)
     302             : ZEND_END_ARG_INFO()
     303             : 
     304             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strrichr, 0, 0, 2)
     305             :         ZEND_ARG_INFO(0, haystack)
     306             :         ZEND_ARG_INFO(0, needle)
     307             :         ZEND_ARG_INFO(0, part)
     308             :         ZEND_ARG_INFO(0, encoding)
     309             : ZEND_END_ARG_INFO()
     310             : 
     311             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_substr_count, 0, 0, 2)
     312             :         ZEND_ARG_INFO(0, haystack)
     313             :         ZEND_ARG_INFO(0, needle)
     314             :         ZEND_ARG_INFO(0, encoding)
     315             : ZEND_END_ARG_INFO()
     316             : 
     317             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_substr, 0, 0, 2)
     318             :         ZEND_ARG_INFO(0, str)
     319             :         ZEND_ARG_INFO(0, start)
     320             :         ZEND_ARG_INFO(0, length)
     321             :         ZEND_ARG_INFO(0, encoding)
     322             : ZEND_END_ARG_INFO()
     323             : 
     324             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strcut, 0, 0, 2)
     325             :         ZEND_ARG_INFO(0, str)
     326             :         ZEND_ARG_INFO(0, start)
     327             :         ZEND_ARG_INFO(0, length)
     328             :         ZEND_ARG_INFO(0, encoding)
     329             : ZEND_END_ARG_INFO()
     330             : 
     331             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strwidth, 0, 0, 1)
     332             :         ZEND_ARG_INFO(0, str)
     333             :         ZEND_ARG_INFO(0, encoding)
     334             : ZEND_END_ARG_INFO()
     335             : 
     336             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strimwidth, 0, 0, 3)
     337             :         ZEND_ARG_INFO(0, str)
     338             :         ZEND_ARG_INFO(0, start)
     339             :         ZEND_ARG_INFO(0, width)
     340             :         ZEND_ARG_INFO(0, trimmarker)
     341             :         ZEND_ARG_INFO(0, encoding)
     342             : ZEND_END_ARG_INFO()
     343             : 
     344             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_convert_encoding, 0, 0, 2)
     345             :         ZEND_ARG_INFO(0, str)
     346             :         ZEND_ARG_INFO(0, to)
     347             :         ZEND_ARG_INFO(0, from)
     348             : ZEND_END_ARG_INFO()
     349             : 
     350             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_convert_case, 0, 0, 2)
     351             :         ZEND_ARG_INFO(0, sourcestring)
     352             :         ZEND_ARG_INFO(0, mode)
     353             :         ZEND_ARG_INFO(0, encoding)
     354             : ZEND_END_ARG_INFO()
     355             : 
     356             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strtoupper, 0, 0, 1)
     357             :         ZEND_ARG_INFO(0, sourcestring)
     358             :         ZEND_ARG_INFO(0, encoding)
     359             : ZEND_END_ARG_INFO()
     360             : 
     361             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strtolower, 0, 0, 1)
     362             :         ZEND_ARG_INFO(0, sourcestring)
     363             :         ZEND_ARG_INFO(0, encoding)
     364             : ZEND_END_ARG_INFO()
     365             : 
     366             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_detect_encoding, 0, 0, 1)
     367             :         ZEND_ARG_INFO(0, str)
     368             :         ZEND_ARG_INFO(0, encoding_list)
     369             :         ZEND_ARG_INFO(0, strict)
     370             : ZEND_END_ARG_INFO()
     371             : 
     372             : ZEND_BEGIN_ARG_INFO(arginfo_mb_list_encodings, 0)
     373             : ZEND_END_ARG_INFO()
     374             : 
     375             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_encoding_aliases, 0, 0, 1)
     376             :         ZEND_ARG_INFO(0, encoding)
     377             : ZEND_END_ARG_INFO()
     378             : 
     379             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_encode_mimeheader, 0, 0, 1)
     380             :         ZEND_ARG_INFO(0, str)
     381             :         ZEND_ARG_INFO(0, charset)
     382             :         ZEND_ARG_INFO(0, transfer)
     383             :         ZEND_ARG_INFO(0, linefeed)
     384             :         ZEND_ARG_INFO(0, indent)
     385             : ZEND_END_ARG_INFO()
     386             : 
     387             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_decode_mimeheader, 0, 0, 1)
     388             :         ZEND_ARG_INFO(0, string)
     389             : ZEND_END_ARG_INFO()
     390             : 
     391             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_convert_kana, 0, 0, 1)
     392             :         ZEND_ARG_INFO(0, str)
     393             :         ZEND_ARG_INFO(0, option)
     394             :         ZEND_ARG_INFO(0, encoding)
     395             : ZEND_END_ARG_INFO()
     396             : 
     397             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_convert_variables, 0, 0, 3)
     398             :         ZEND_ARG_INFO(0, to)
     399             :         ZEND_ARG_INFO(0, from)
     400             :         ZEND_ARG_VARIADIC_INFO(1, vars)
     401             : ZEND_END_ARG_INFO()
     402             : 
     403             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_encode_numericentity, 0, 0, 2)
     404             :         ZEND_ARG_INFO(0, string)
     405             :         ZEND_ARG_INFO(0, convmap)
     406             :         ZEND_ARG_INFO(0, encoding)
     407             :         ZEND_ARG_INFO(0, is_hex)
     408             : ZEND_END_ARG_INFO()
     409             : 
     410             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_decode_numericentity, 0, 0, 2)
     411             :         ZEND_ARG_INFO(0, string)
     412             :         ZEND_ARG_INFO(0, convmap)
     413             :         ZEND_ARG_INFO(0, encoding)
     414             : ZEND_END_ARG_INFO()
     415             : 
     416             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_send_mail, 0, 0, 3)
     417             :         ZEND_ARG_INFO(0, to)
     418             :         ZEND_ARG_INFO(0, subject)
     419             :         ZEND_ARG_INFO(0, message)
     420             :         ZEND_ARG_INFO(0, additional_headers)
     421             :         ZEND_ARG_INFO(0, additional_parameters)
     422             : ZEND_END_ARG_INFO()
     423             : 
     424             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_get_info, 0, 0, 0)
     425             :         ZEND_ARG_INFO(0, type)
     426             : ZEND_END_ARG_INFO()
     427             : 
     428             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_check_encoding, 0, 0, 0)
     429             :         ZEND_ARG_INFO(0, var)
     430             :         ZEND_ARG_INFO(0, encoding)
     431             : ZEND_END_ARG_INFO()
     432             : 
     433             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_regex_encoding, 0, 0, 0)
     434             :         ZEND_ARG_INFO(0, encoding)
     435             : ZEND_END_ARG_INFO()
     436             : 
     437             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg, 0, 0, 2)
     438             :         ZEND_ARG_INFO(0, pattern)
     439             :         ZEND_ARG_INFO(0, string)
     440             :         ZEND_ARG_INFO(1, registers)
     441             : ZEND_END_ARG_INFO()
     442             : 
     443             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_eregi, 0, 0, 2)
     444             :         ZEND_ARG_INFO(0, pattern)
     445             :         ZEND_ARG_INFO(0, string)
     446             :         ZEND_ARG_INFO(1, registers)
     447             : ZEND_END_ARG_INFO()
     448             : 
     449             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_replace, 0, 0, 3)
     450             :         ZEND_ARG_INFO(0, pattern)
     451             :         ZEND_ARG_INFO(0, replacement)
     452             :         ZEND_ARG_INFO(0, string)
     453             :         ZEND_ARG_INFO(0, option)
     454             : ZEND_END_ARG_INFO()
     455             : 
     456             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_eregi_replace, 0, 0, 3)
     457             :         ZEND_ARG_INFO(0, pattern)
     458             :         ZEND_ARG_INFO(0, replacement)
     459             :         ZEND_ARG_INFO(0, string)
     460             : ZEND_END_ARG_INFO()
     461             : 
     462             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_replace_callback, 0, 0, 3)
     463             :         ZEND_ARG_INFO(0, pattern)
     464             :         ZEND_ARG_INFO(0, callback)
     465             :         ZEND_ARG_INFO(0, string)
     466             :         ZEND_ARG_INFO(0, option)
     467             : ZEND_END_ARG_INFO()
     468             : 
     469             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_split, 0, 0, 2)
     470             :         ZEND_ARG_INFO(0, pattern)
     471             :         ZEND_ARG_INFO(0, string)
     472             :         ZEND_ARG_INFO(0, limit)
     473             : ZEND_END_ARG_INFO()
     474             : 
     475             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_match, 0, 0, 2)
     476             :         ZEND_ARG_INFO(0, pattern)
     477             :         ZEND_ARG_INFO(0, string)
     478             :         ZEND_ARG_INFO(0, option)
     479             : ZEND_END_ARG_INFO()
     480             : 
     481             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_search, 0, 0, 0)
     482             :         ZEND_ARG_INFO(0, pattern)
     483             :         ZEND_ARG_INFO(0, option)
     484             : ZEND_END_ARG_INFO()
     485             : 
     486             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_search_pos, 0, 0, 0)
     487             :         ZEND_ARG_INFO(0, pattern)
     488             :         ZEND_ARG_INFO(0, option)
     489             : ZEND_END_ARG_INFO()
     490             : 
     491             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_search_regs, 0, 0, 0)
     492             :         ZEND_ARG_INFO(0, pattern)
     493             :         ZEND_ARG_INFO(0, option)
     494             : ZEND_END_ARG_INFO()
     495             : 
     496             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_search_init, 0, 0, 1)
     497             :         ZEND_ARG_INFO(0, string)
     498             :         ZEND_ARG_INFO(0, pattern)
     499             :         ZEND_ARG_INFO(0, option)
     500             : ZEND_END_ARG_INFO()
     501             : 
     502             : ZEND_BEGIN_ARG_INFO(arginfo_mb_ereg_search_getregs, 0)
     503             : ZEND_END_ARG_INFO()
     504             : 
     505             : ZEND_BEGIN_ARG_INFO(arginfo_mb_ereg_search_getpos, 0)
     506             : ZEND_END_ARG_INFO()
     507             : 
     508             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_search_setpos, 0, 0, 1)
     509             :         ZEND_ARG_INFO(0, position)
     510             : ZEND_END_ARG_INFO()
     511             : 
     512             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_regex_set_options, 0, 0, 0)
     513             :         ZEND_ARG_INFO(0, options)
     514             : ZEND_END_ARG_INFO()
     515             : /* }}} */
     516             : 
     517             : /* {{{ zend_function_entry mbstring_functions[] */
     518             : const zend_function_entry mbstring_functions[] = {
     519             :         PHP_FE(mb_convert_case,                 arginfo_mb_convert_case)
     520             :         PHP_FE(mb_strtoupper,                   arginfo_mb_strtoupper)
     521             :         PHP_FE(mb_strtolower,                   arginfo_mb_strtolower)
     522             :         PHP_FE(mb_language,                             arginfo_mb_language)
     523             :         PHP_FE(mb_internal_encoding,    arginfo_mb_internal_encoding)
     524             :         PHP_FE(mb_http_input,                   arginfo_mb_http_input)
     525             :         PHP_FE(mb_http_output,                  arginfo_mb_http_output)
     526             :         PHP_FE(mb_detect_order,                 arginfo_mb_detect_order)
     527             :         PHP_FE(mb_substitute_character, arginfo_mb_substitute_character)
     528             :         PHP_FE(mb_parse_str,                    arginfo_mb_parse_str)
     529             :         PHP_FE(mb_output_handler,               arginfo_mb_output_handler)
     530             :         PHP_FE(mb_preferred_mime_name,  arginfo_mb_preferred_mime_name)
     531             :         PHP_FE(mb_strlen,                               arginfo_mb_strlen)
     532             :         PHP_FE(mb_strpos,                               arginfo_mb_strpos)
     533             :         PHP_FE(mb_strrpos,                              arginfo_mb_strrpos)
     534             :         PHP_FE(mb_stripos,                              arginfo_mb_stripos)
     535             :         PHP_FE(mb_strripos,                             arginfo_mb_strripos)
     536             :         PHP_FE(mb_strstr,                               arginfo_mb_strstr)
     537             :         PHP_FE(mb_strrchr,                              arginfo_mb_strrchr)
     538             :         PHP_FE(mb_stristr,                              arginfo_mb_stristr)
     539             :         PHP_FE(mb_strrichr,                             arginfo_mb_strrichr)
     540             :         PHP_FE(mb_substr_count,                 arginfo_mb_substr_count)
     541             :         PHP_FE(mb_substr,                               arginfo_mb_substr)
     542             :         PHP_FE(mb_strcut,                               arginfo_mb_strcut)
     543             :         PHP_FE(mb_strwidth,                             arginfo_mb_strwidth)
     544             :         PHP_FE(mb_strimwidth,                   arginfo_mb_strimwidth)
     545             :         PHP_FE(mb_convert_encoding,             arginfo_mb_convert_encoding)
     546             :         PHP_FE(mb_detect_encoding,              arginfo_mb_detect_encoding)
     547             :         PHP_FE(mb_list_encodings,               arginfo_mb_list_encodings)
     548             :         PHP_FE(mb_encoding_aliases,             arginfo_mb_encoding_aliases)
     549             :         PHP_FE(mb_convert_kana,                 arginfo_mb_convert_kana)
     550             :         PHP_FE(mb_encode_mimeheader,    arginfo_mb_encode_mimeheader)
     551             :         PHP_FE(mb_decode_mimeheader,    arginfo_mb_decode_mimeheader)
     552             :         PHP_FE(mb_convert_variables,    arginfo_mb_convert_variables)
     553             :         PHP_FE(mb_encode_numericentity, arginfo_mb_encode_numericentity)
     554             :         PHP_FE(mb_decode_numericentity, arginfo_mb_decode_numericentity)
     555             :         PHP_FE(mb_send_mail,                    arginfo_mb_send_mail)
     556             :         PHP_FE(mb_get_info,                             arginfo_mb_get_info)
     557             :         PHP_FE(mb_check_encoding,               arginfo_mb_check_encoding)
     558             : #if HAVE_MBREGEX
     559             :         PHP_MBREGEX_FUNCTION_ENTRIES
     560             : #endif
     561             :         PHP_FE_END
     562             : };
     563             : /* }}} */
     564             : 
     565             : /* {{{ zend_module_entry mbstring_module_entry */
     566             : zend_module_entry mbstring_module_entry = {
     567             :         STANDARD_MODULE_HEADER,
     568             :         "mbstring",
     569             :         mbstring_functions,
     570             :         PHP_MINIT(mbstring),
     571             :         PHP_MSHUTDOWN(mbstring),
     572             :         PHP_RINIT(mbstring),
     573             :         PHP_RSHUTDOWN(mbstring),
     574             :         PHP_MINFO(mbstring),
     575             :         PHP_MBSTRING_VERSION,
     576             :         PHP_MODULE_GLOBALS(mbstring),
     577             :         PHP_GINIT(mbstring),
     578             :         PHP_GSHUTDOWN(mbstring),
     579             :         NULL,
     580             :         STANDARD_MODULE_PROPERTIES_EX
     581             : };
     582             : /* }}} */
     583             : 
     584             : /* {{{ static sapi_post_entry php_post_entries[] */
     585             : static sapi_post_entry php_post_entries[] = {
     586             :         { DEFAULT_POST_CONTENT_TYPE, sizeof(DEFAULT_POST_CONTENT_TYPE)-1, sapi_read_standard_form_data, php_std_post_handler },
     587             :         { MULTIPART_CONTENT_TYPE,    sizeof(MULTIPART_CONTENT_TYPE)-1,    NULL,                         rfc1867_post_handler },
     588             :         { NULL, 0, NULL, NULL }
     589             : };
     590             : /* }}} */
     591             : 
     592             : #ifdef COMPILE_DL_MBSTRING
     593             : #ifdef ZTS
     594             : ZEND_TSRMLS_CACHE_DEFINE();
     595             : #endif
     596             : ZEND_GET_MODULE(mbstring)
     597             : #endif
     598             : 
     599       44926 : static char *get_internal_encoding(void) {
     600       44926 :         if (PG(internal_encoding) && PG(internal_encoding)[0]) {
     601           0 :                 return PG(internal_encoding);
     602       44926 :         } else if (SG(default_charset)) {
     603       44926 :                 return SG(default_charset);
     604             :         }
     605           0 :         return "";
     606             : }
     607             : 
     608       45120 : static char *get_input_encoding(void) {
     609       45120 :         if (PG(input_encoding) && PG(input_encoding)[0]) {
     610           0 :                 return PG(input_encoding);
     611       45120 :         } else if (SG(default_charset)) {
     612       45120 :                 return SG(default_charset);
     613             :         }
     614           0 :         return "";
     615             : }
     616             : 
     617       22562 : static char *get_output_encoding(void) {
     618       22562 :         if (PG(output_encoding) && PG(output_encoding)[0]) {
     619           0 :                 return PG(output_encoding);
     620       22562 :         } else if (SG(default_charset)) {
     621       22562 :                 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      173069 : 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      173069 :         int size, bauto, ret = SUCCESS;
     691             :         size_t n;
     692             :         char *p, *p1, *p2, *endp, *tmpstr;
     693             :         const mbfl_encoding **entry, **list;
     694             : 
     695      173069 :         list = NULL;
     696      173069 :         if (value == NULL || value_length <= 0) {
     697       22555 :                 if (return_list) {
     698       22555 :                         *return_list = NULL;
     699             :                 }
     700       22555 :                 if (return_size) {
     701       22555 :                         *return_size = 0;
     702             :                 }
     703       22555 :                 return FAILURE;
     704             :         } else {
     705             :                 /* copy the value string for work */
     706      150514 :                 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      150514 :                         tmpstr = (char *)estrndup(value, value_length);
     712      150514 :                 if (tmpstr == NULL) {
     713           0 :                         return FAILURE;
     714             :                 }
     715             :                 /* count the number of listed encoding names */
     716      150514 :                 endp = tmpstr + value_length;
     717      150514 :                 n = 1;
     718      150514 :                 p1 = tmpstr;
     719      301058 :                 while ((p2 = (char*)php_memnstr(p1, ",", 1, endp)) != NULL) {
     720          30 :                         p1 = p2 + 1;
     721          30 :                         n++;
     722             :                 }
     723      150514 :                 size = n + MBSTRG(default_detect_order_list_size);
     724             :                 /* make list */
     725      150514 :                 list = (const mbfl_encoding **)pecalloc(size, sizeof(mbfl_encoding*), persistent);
     726      150514 :                 if (list != NULL) {
     727      150514 :                         entry = list;
     728      150514 :                         n = 0;
     729      150514 :                         bauto = 0;
     730      150514 :                         p1 = tmpstr;
     731             :                         do {
     732      150544 :                                 p2 = p = (char*)php_memnstr(p1, ",", 1, endp);
     733      150544 :                                 if (p == NULL) {
     734      150514 :                                         p = endp;
     735             :                                 }
     736      150544 :                                 *p = '\0';
     737             :                                 /* trim spaces */
     738      301088 :                                 while (p1 < p && (*p1 == ' ' || *p1 == '\t')) {
     739           0 :                                         p1++;
     740             :                                 }
     741      150544 :                                 p--;
     742      301088 :                                 while (p > p1 && (*p == ' ' || *p == '\t')) {
     743           0 :                                         *p = '\0';
     744           0 :                                         p--;
     745             :                                 }
     746             :                                 /* convert to the encoding number and check encoding */
     747      150544 :                                 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      150532 :                                         const mbfl_encoding *encoding = mbfl_name2encoding(p1);
     760      150532 :                                         if (encoding) {
     761      150517 :                                                 *entry++ = encoding;
     762      150517 :                                                 n++;
     763             :                                         } else {
     764          15 :                                                 ret = 0;
     765             :                                         }
     766             :                                 }
     767      150544 :                                 p1 = p2 + 1;
     768      150544 :                         } while (n < size && p2 != NULL);
     769      150514 :                         if (n > 0) {
     770      150499 :                                 if (return_list) {
     771      150499 :                                         *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      150514 :                         if (return_size) {
     783      150514 :                                 *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      150514 :                 efree(tmpstr);
     795             :         }
     796             : 
     797      150514 :         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      112894 : static const zend_encoding* php_mb_zend_encoding_fetcher(const char *encoding_name)
     882             : {
     883      112894 :         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      135420 : 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      135420 :         return php_mb_parse_encoding_list(encoding_list, encoding_list_len, (const mbfl_encoding ***)return_list, return_size, persistent);
     966             : }
     967             : 
     968         157 : static const zend_encoding *php_mb_zend_internal_encoding_getter(void)
     969             : {
     970         157 :         return (const zend_encoding *)MBSTRG(internal_encoding);
     971             : }
     972             : 
     973       22524 : static int php_mb_zend_internal_encoding_setter(const zend_encoding *encoding)
     974             : {
     975       22524 :         MBSTRG(internal_encoding) = (const mbfl_encoding *)encoding;
     976       22524 :         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       22574 : 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       45148 :         if ((err_code = onig_new(&retval,
    1005             :                         (const OnigUChar *)pattern,
    1006       22574 :                         (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       22574 :         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       22610 : static void _php_mb_free_regex(void *opaque)
    1029             : {
    1030       22610 :         onig_free((php_mb_regex_t *)opaque);
    1031       22610 : }
    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       22600 : 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       22600 :         *plist = (enum mbfl_no_encoding *) php_mb_default_identify_list_neut;
    1071       22600 :         *plist_size = sizeof(php_mb_default_identify_list_neut) / sizeof(php_mb_default_identify_list_neut[0]);
    1072             : 
    1073      203226 :         for (i = 0; i < sizeof(php_mb_default_identify_list) / sizeof(php_mb_default_identify_list[0]); i++) {
    1074      203222 :                 if (php_mb_default_identify_list[i].lang == lang) {
    1075       22596 :                         *plist = (enum mbfl_no_encoding *)php_mb_default_identify_list[i].list;
    1076       22596 :                         *plist_size = php_mb_default_identify_list[i].list_size;
    1077       22596 :                         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       22600 : static PHP_INI_MH(OnUpdate_mbstring_language)
    1205             : {
    1206             :         enum mbfl_no_language no_language;
    1207             : 
    1208       22600 :         no_language = mbfl_name2no_language(ZSTR_VAL(new_value));
    1209       22600 :         if (no_language == mbfl_no_language_invalid) {
    1210           0 :                 MBSTRG(language) = mbfl_no_language_neutral;
    1211           0 :                 return FAILURE;
    1212             :         }
    1213       22600 :         MBSTRG(language) = no_language;
    1214       22600 :         php_mb_nls_get_default_detect_order_list(no_language, &MBSTRG(default_detect_order_list), &MBSTRG(default_detect_order_list_size));
    1215       22600 :         return SUCCESS;
    1216             : }
    1217             : /* }}} */
    1218             : 
    1219             : /* {{{ static PHP_INI_MH(OnUpdate_mbstring_detect_order) */
    1220       22570 : static PHP_INI_MH(OnUpdate_mbstring_detect_order)
    1221             : {
    1222             :         const mbfl_encoding **list;
    1223             :         size_t size;
    1224             : 
    1225       22570 :         if (!new_value) {
    1226       22568 :                 if (MBSTRG(detect_order_list)) {
    1227           0 :                         pefree(MBSTRG(detect_order_list), 1);
    1228             :                 }
    1229       22568 :                 MBSTRG(detect_order_list) = NULL;
    1230       22568 :                 MBSTRG(detect_order_list_size) = 0;
    1231       22568 :                 return SUCCESS;
    1232             :         }
    1233             : 
    1234           2 :         if (FAILURE == php_mb_parse_encoding_list(ZSTR_VAL(new_value), ZSTR_LEN(new_value), &list, &size, 1)) {
    1235           0 :                 return FAILURE;
    1236             :         }
    1237             : 
    1238           2 :         if (MBSTRG(detect_order_list)) {
    1239           0 :                 pefree(MBSTRG(detect_order_list), 1);
    1240             :         }
    1241           2 :         MBSTRG(detect_order_list) = list;
    1242           2 :         MBSTRG(detect_order_list_size) = size;
    1243           2 :         return SUCCESS;
    1244             : }
    1245             : /* }}} */
    1246             : 
    1247             : /* {{{ static PHP_INI_MH(OnUpdate_mbstring_http_input) */
    1248       22572 : static PHP_INI_MH(OnUpdate_mbstring_http_input)
    1249             : {
    1250             :         const mbfl_encoding **list;
    1251             :         size_t size;
    1252             : 
    1253       22572 :         if (!new_value) {
    1254       22560 :                 if (MBSTRG(http_input_list)) {
    1255           0 :                         pefree(MBSTRG(http_input_list), 1);
    1256             :                 }
    1257       22560 :                 if (SUCCESS == php_mb_parse_encoding_list(get_input_encoding(), strlen(get_input_encoding())+1, &list, &size, 1)) {
    1258       22560 :                         MBSTRG(http_input_list) = list;
    1259       22560 :                         MBSTRG(http_input_list_size) = size;
    1260       22560 :                         return SUCCESS;
    1261             :                 }
    1262           0 :                 MBSTRG(http_input_list) = NULL;
    1263           0 :                 MBSTRG(http_input_list_size) = 0;
    1264           0 :                 return SUCCESS;
    1265             :         }
    1266             : 
    1267          12 :         if (FAILURE == php_mb_parse_encoding_list(ZSTR_VAL(new_value), ZSTR_LEN(new_value), &list, &size, 1)) {
    1268           0 :                 return FAILURE;
    1269             :         }
    1270             : 
    1271          12 :         if (MBSTRG(http_input_list)) {
    1272           2 :                 pefree(MBSTRG(http_input_list), 1);
    1273             :         }
    1274          12 :         MBSTRG(http_input_list) = list;
    1275          12 :         MBSTRG(http_input_list_size) = size;
    1276             : 
    1277          12 :         if (stage & (PHP_INI_STAGE_ACTIVATE | PHP_INI_STAGE_RUNTIME)) {
    1278           1 :                 php_error_docref("ref.mbstring", E_DEPRECATED, "Use of mbstring.http_input is deprecated");
    1279             :         }
    1280             : 
    1281          12 :         return SUCCESS;
    1282             : }
    1283             : /* }}} */
    1284             : 
    1285             : /* {{{ static PHP_INI_MH(OnUpdate_mbstring_http_output) */
    1286       22572 : static PHP_INI_MH(OnUpdate_mbstring_http_output)
    1287             : {
    1288             :         const mbfl_encoding *encoding;
    1289             : 
    1290       45121 :         if (new_value == NULL || ZSTR_LEN(new_value) == 0) {
    1291       22562 :                 encoding = mbfl_name2encoding(get_output_encoding());
    1292       22562 :                 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(ZSTR_VAL(new_value));
    1299          10 :                 if (!encoding) {
    1300           0 :                         MBSTRG(http_output_encoding) = &mbfl_encoding_pass;
    1301           0 :                         MBSTRG(current_http_output_encoding) = &mbfl_encoding_pass;
    1302           0 :                         return FAILURE;
    1303             :                 }
    1304             :         }
    1305       22559 :         MBSTRG(http_output_encoding) = encoding;
    1306       22559 :         MBSTRG(current_http_output_encoding) = encoding;
    1307             : 
    1308       22559 :         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       22559 :         return SUCCESS;
    1313             : }
    1314             : /* }}} */
    1315             : 
    1316             : /* {{{ static _php_mb_ini_mbstring_internal_encoding_set */
    1317       67700 : int _php_mb_ini_mbstring_internal_encoding_set(const char *new_value, uint new_value_length)
    1318             : {
    1319             :         const mbfl_encoding *encoding;
    1320             : 
    1321       67700 :         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       44918 :                 encoding = mbfl_no2encoding(mbfl_no_encoding_utf8);
    1324             :         }
    1325       67700 :         MBSTRG(internal_encoding) = encoding;
    1326       67700 :         MBSTRG(current_internal_encoding) = encoding;
    1327             : #if HAVE_MBREGEX
    1328             :         {
    1329       67700 :                 const char *enc_name = new_value;
    1330       67700 :                 if (FAILURE == php_mb_regex_set_default_mbctype(enc_name)) {
    1331             :                         /* falls back to UTF-8 if an unknown encoding name is given */
    1332       44972 :                         enc_name = "UTF-8";
    1333       44972 :                         php_mb_regex_set_default_mbctype(enc_name);
    1334             :                 }
    1335       67700 :                 php_mb_regex_set_mbctype(new_value);
    1336             :         }
    1337             : #endif
    1338       67700 :         return SUCCESS;
    1339             : }
    1340             : /* }}} */
    1341             : 
    1342             : /* {{{ static PHP_INI_MH(OnUpdate_mbstring_internal_encoding) */
    1343       22574 : static PHP_INI_MH(OnUpdate_mbstring_internal_encoding)
    1344             : {
    1345       22574 :         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       22574 :         if (OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage) == FAILURE) {
    1350           0 :                 return FAILURE;
    1351             :         }
    1352             : 
    1353       22574 :         if (stage & (PHP_INI_STAGE_STARTUP | PHP_INI_STAGE_SHUTDOWN | PHP_INI_STAGE_RUNTIME)) {
    1354       22572 :                 if (new_value && ZSTR_LEN(new_value)) {
    1355         109 :                         return _php_mb_ini_mbstring_internal_encoding_set(ZSTR_VAL(new_value), ZSTR_LEN(new_value));
    1356             :                 } else {
    1357       22463 :                         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       22570 : static PHP_INI_MH(OnUpdate_mbstring_substitute_character)
    1373             : {
    1374             :         int c;
    1375       22570 :         char *endptr = NULL;
    1376             : 
    1377       22570 :         if (new_value != NULL) {
    1378           2 :                 if (strcasecmp("none", ZSTR_VAL(new_value)) == 0) {
    1379           0 :                         MBSTRG(filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE;
    1380           0 :                         MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE;
    1381           2 :                 } else if (strcasecmp("long", ZSTR_VAL(new_value)) == 0) {
    1382           0 :                         MBSTRG(filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_LONG;
    1383           0 :                         MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_LONG;
    1384           2 :                 } else if (strcasecmp("entity", ZSTR_VAL(new_value)) == 0) {
    1385           0 :                         MBSTRG(filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_ENTITY;
    1386           0 :                         MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_ENTITY;
    1387             :                 } else {
    1388           2 :                         MBSTRG(filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR;
    1389           2 :                         MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR;
    1390           2 :                         if (ZSTR_LEN(new_value) > 0) {
    1391           2 :                                 c = strtol(ZSTR_VAL(new_value), &endptr, 0);
    1392           2 :                                 if (*endptr == '\0') {
    1393           2 :                                         MBSTRG(filter_illegal_substchar) = c;
    1394           2 :                                         MBSTRG(current_filter_illegal_substchar) = c;
    1395             :                                 }
    1396             :                         }
    1397             :                 }
    1398             :         } else {
    1399       22568 :                 MBSTRG(filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR;
    1400       22568 :                 MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR;
    1401       22568 :                 MBSTRG(filter_illegal_substchar) = 0x3f;        /* '?' */
    1402       22568 :                 MBSTRG(current_filter_illegal_substchar) = 0x3f;        /* '?' */
    1403             :         }
    1404             : 
    1405       22570 :         return SUCCESS;
    1406             : }
    1407             : /* }}} */
    1408             : 
    1409             : /* {{{ static PHP_INI_MH(OnUpdate_mbstring_encoding_translation) */
    1410       22570 : static PHP_INI_MH(OnUpdate_mbstring_encoding_translation)
    1411             : {
    1412       22570 :         if (new_value == NULL) {
    1413           0 :                 return FAILURE;
    1414             :         }
    1415             : 
    1416       22570 :         OnUpdateBool(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
    1417             : 
    1418       22570 :         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       22556 :                 sapi_unregister_post_entry(mbstr_post_entries);
    1423       22556 :                 sapi_register_post_entries(php_post_entries);
    1424             :         }
    1425             : 
    1426       22570 :         return SUCCESS;
    1427             : }
    1428             : /* }}} */
    1429             : 
    1430             : /* {{{ static PHP_INI_MH(OnUpdate_mbstring_http_output_conv_mimetypes */
    1431       22574 : static PHP_INI_MH(OnUpdate_mbstring_http_output_conv_mimetypes)
    1432             : {
    1433             :         zend_string *tmp;
    1434       22574 :         void *re = NULL;
    1435             : 
    1436       22574 :         if (!new_value) {
    1437           0 :                 new_value = entry->orig_value;
    1438             :         }
    1439       22574 :         tmp = php_trim(new_value, NULL, 0, 3);
    1440             : 
    1441       22574 :         if (ZSTR_LEN(tmp) > 0) {
    1442       22574 :                 if (!(re = _php_mb_compile_regex(ZSTR_VAL(tmp)))) {
    1443             :                         zend_string_release(tmp);
    1444           0 :                         return FAILURE;
    1445             :                 }
    1446             :         }
    1447             : 
    1448       22574 :         if (MBSTRG(http_output_conv_mimetypes)) {
    1449           4 :                 _php_mb_free_regex(MBSTRG(http_output_conv_mimetypes));
    1450             :         }
    1451             : 
    1452       22574 :         MBSTRG(http_output_conv_mimetypes) = re;
    1453             : 
    1454             :         zend_string_release(tmp);
    1455       22574 :         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       22570 : static PHP_GINIT_FUNCTION(mbstring)
    1489             : {
    1490             : #if defined(COMPILE_DL_MBSTRING) && defined(ZTS)
    1491             : ZEND_TSRMLS_CACHE_UPDATE();
    1492             : #endif
    1493             : 
    1494       22570 :         mbstring_globals->language = mbfl_no_language_uni;
    1495       22570 :         mbstring_globals->internal_encoding = NULL;
    1496       22570 :         mbstring_globals->current_internal_encoding = mbstring_globals->internal_encoding;
    1497       22570 :         mbstring_globals->http_output_encoding = &mbfl_encoding_pass;
    1498       22570 :         mbstring_globals->current_http_output_encoding = &mbfl_encoding_pass;
    1499       22570 :         mbstring_globals->http_input_identify = NULL;
    1500       22570 :         mbstring_globals->http_input_identify_get = NULL;
    1501       22570 :         mbstring_globals->http_input_identify_post = NULL;
    1502       22570 :         mbstring_globals->http_input_identify_cookie = NULL;
    1503       22570 :         mbstring_globals->http_input_identify_string = NULL;
    1504       22570 :         mbstring_globals->http_input_list = NULL;
    1505       22570 :         mbstring_globals->http_input_list_size = 0;
    1506       22570 :         mbstring_globals->detect_order_list = NULL;
    1507       22570 :         mbstring_globals->detect_order_list_size = 0;
    1508       22570 :         mbstring_globals->current_detect_order_list = NULL;
    1509       22570 :         mbstring_globals->current_detect_order_list_size = 0;
    1510       22570 :         mbstring_globals->default_detect_order_list = (enum mbfl_no_encoding *) php_mb_default_identify_list_neut;
    1511       22570 :         mbstring_globals->default_detect_order_list_size = sizeof(php_mb_default_identify_list_neut) / sizeof(php_mb_default_identify_list_neut[0]);
    1512       22570 :         mbstring_globals->filter_illegal_mode = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR;
    1513       22570 :         mbstring_globals->filter_illegal_substchar = 0x3f;   /* '?' */
    1514       22570 :         mbstring_globals->current_filter_illegal_mode = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR;
    1515       22570 :         mbstring_globals->current_filter_illegal_substchar = 0x3f;   /* '?' */
    1516       22570 :         mbstring_globals->illegalchars = 0;
    1517       22570 :         mbstring_globals->func_overload = 0;
    1518       22570 :         mbstring_globals->encoding_translation = 0;
    1519       22570 :         mbstring_globals->strict_detection = 0;
    1520       22570 :         mbstring_globals->outconv = NULL;
    1521       22570 :         mbstring_globals->http_output_conv_mimetypes = NULL;
    1522             : #if HAVE_MBREGEX
    1523       22570 :         mbstring_globals->mb_regex_globals = php_mb_regex_globals_alloc();
    1524             : #endif
    1525       22570 : }
    1526             : /* }}} */
    1527             : 
    1528             : /* {{{ PHP_GSHUTDOWN_FUNCTION */
    1529       22606 : static PHP_GSHUTDOWN_FUNCTION(mbstring)
    1530             : {
    1531       22606 :         if (mbstring_globals->http_input_list) {
    1532       22593 :                 free(mbstring_globals->http_input_list);
    1533             :         }
    1534       22606 :         if (mbstring_globals->detect_order_list) {
    1535           2 :                 free(mbstring_globals->detect_order_list);
    1536             :         }
    1537       22606 :         if (mbstring_globals->http_output_conv_mimetypes) {
    1538       22606 :                 _php_mb_free_regex(mbstring_globals->http_output_conv_mimetypes);
    1539             :         }
    1540             : #if HAVE_MBREGEX
    1541       22606 :         php_mb_regex_globals_free(mbstring_globals->mb_regex_globals);
    1542             : #endif
    1543       22606 : }
    1544             : /* }}} */
    1545             : 
    1546             : /* {{{ PHP_MINIT_FUNCTION(mbstring) */
    1547       22570 : PHP_MINIT_FUNCTION(mbstring)
    1548             : {
    1549             : #if defined(COMPILE_DL_MBSTRING) && defined(ZTS)
    1550             : ZEND_TSRMLS_CACHE_UPDATE();
    1551             : #endif
    1552       22570 :         __mbfl_allocators = &_php_mb_allocators;
    1553             : 
    1554       22570 :         REGISTER_INI_ENTRIES();
    1555             : 
    1556             :         /* This is a global handler. Should not be set in a per-request handler. */
    1557       22570 :         sapi_register_treat_data(mbstr_treat_data);
    1558             : 
    1559             :         /* Post handlers are stored in the thread-local context. */
    1560       22570 :         if (MBSTRG(encoding_translation)) {
    1561          14 :                 sapi_register_post_entries(mbstr_post_entries);
    1562             :         }
    1563             : 
    1564       22570 :         REGISTER_LONG_CONSTANT("MB_OVERLOAD_MAIL", MB_OVERLOAD_MAIL, CONST_CS | CONST_PERSISTENT);
    1565       22570 :         REGISTER_LONG_CONSTANT("MB_OVERLOAD_STRING", MB_OVERLOAD_STRING, CONST_CS | CONST_PERSISTENT);
    1566       22570 :         REGISTER_LONG_CONSTANT("MB_OVERLOAD_REGEX", MB_OVERLOAD_REGEX, CONST_CS | CONST_PERSISTENT);
    1567             : 
    1568       22570 :         REGISTER_LONG_CONSTANT("MB_CASE_UPPER", PHP_UNICODE_CASE_UPPER, CONST_CS | CONST_PERSISTENT);
    1569       22570 :         REGISTER_LONG_CONSTANT("MB_CASE_LOWER", PHP_UNICODE_CASE_LOWER, CONST_CS | CONST_PERSISTENT);
    1570       22570 :         REGISTER_LONG_CONSTANT("MB_CASE_TITLE", PHP_UNICODE_CASE_TITLE, CONST_CS | CONST_PERSISTENT);
    1571             : 
    1572             : #if HAVE_MBREGEX
    1573       22570 :         PHP_MINIT(mb_regex) (INIT_FUNC_ARGS_PASSTHRU);
    1574             : #endif
    1575             : 
    1576       22570 :         if (FAILURE == zend_multibyte_set_functions(&php_mb_zend_multibyte_functions)) {
    1577           0 :                 return FAILURE;
    1578             :         }
    1579             : 
    1580       22570 :         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       22570 :         return SUCCESS;
    1589             : }
    1590             : /* }}} */
    1591             : 
    1592             : /* {{{ PHP_MSHUTDOWN_FUNCTION(mbstring) */
    1593       22606 : PHP_MSHUTDOWN_FUNCTION(mbstring)
    1594             : {
    1595       22606 :         UNREGISTER_INI_ENTRIES();
    1596             : 
    1597             : #if HAVE_MBREGEX
    1598       22606 :         PHP_MSHUTDOWN(mb_regex) (INIT_FUNC_ARGS_PASSTHRU);
    1599             : #endif
    1600             : 
    1601       22606 :         return SUCCESS;
    1602             : }
    1603             : /* }}} */
    1604             : 
    1605             : /* {{{ PHP_RINIT_FUNCTION(mbstring) */
    1606       22524 : PHP_RINIT_FUNCTION(mbstring)
    1607             : {
    1608             :         zend_function *func, *orig;
    1609             :         const struct mb_overload_def *p;
    1610             : 
    1611       22524 :         MBSTRG(current_internal_encoding) = MBSTRG(internal_encoding);
    1612       22524 :         MBSTRG(current_http_output_encoding) = MBSTRG(http_output_encoding);
    1613       22524 :         MBSTRG(current_filter_illegal_mode) = MBSTRG(filter_illegal_mode);
    1614       22524 :         MBSTRG(current_filter_illegal_substchar) = MBSTRG(filter_illegal_substchar);
    1615             : 
    1616       22524 :         MBSTRG(illegalchars) = 0;
    1617             : 
    1618       22524 :         php_mb_populate_current_detect_order_list();
    1619             : 
    1620             :         /* override original function. */
    1621       22524 :         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       22524 :         PHP_RINIT(mb_regex) (INIT_FUNC_ARGS_PASSTHRU);
    1652             : #endif
    1653       22524 :         zend_multibyte_set_internal_encoding((const zend_encoding *)MBSTRG(internal_encoding));
    1654             : 
    1655       22524 :         return SUCCESS;
    1656             : }
    1657             : /* }}} */
    1658             : 
    1659             : /* {{{ PHP_RSHUTDOWN_FUNCTION(mbstring) */
    1660       22562 : PHP_RSHUTDOWN_FUNCTION(mbstring)
    1661             : {
    1662             :         const struct mb_overload_def *p;
    1663             :         zend_function *orig;
    1664             : 
    1665       22562 :         if (MBSTRG(current_detect_order_list) != NULL) {
    1666       22562 :                 efree(MBSTRG(current_detect_order_list));
    1667       22562 :                 MBSTRG(current_detect_order_list) = NULL;
    1668       22562 :                 MBSTRG(current_detect_order_list_size) = 0;
    1669             :         }
    1670       22562 :         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       22562 :         MBSTRG(http_input_identify) = NULL;
    1678       22562 :         MBSTRG(http_input_identify_post) = NULL;
    1679       22562 :         MBSTRG(http_input_identify_get) = NULL;
    1680       22562 :         MBSTRG(http_input_identify_cookie) = NULL;
    1681       22562 :         MBSTRG(http_input_identify_string) = NULL;
    1682             : 
    1683             :         /*  clear overloaded function. */
    1684       22562 :         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       22562 :         PHP_RSHUTDOWN(mb_regex) (INIT_FUNC_ARGS_PASSTHRU);
    1701             : #endif
    1702             : 
    1703       22562 :         return SUCCESS;
    1704             : }
    1705             : /* }}} */
    1706             : 
    1707             : /* {{{ PHP_MINFO_FUNCTION(mbstring) */
    1708         149 : PHP_MINFO_FUNCTION(mbstring)
    1709             : {
    1710         149 :         php_info_print_table_start();
    1711         149 :         php_info_print_table_row(2, "Multibyte Support", "enabled");
    1712         149 :         php_info_print_table_row(2, "Multibyte string engine", "libmbfl");
    1713         149 :         php_info_print_table_row(2, "HTTP input encoding translation", MBSTRG(encoding_translation) ? "enabled": "disabled");
    1714             :         {
    1715             :                 char tmp[256];
    1716         149 :                 snprintf(tmp, sizeof(tmp), "%d.%d.%d", MBFL_VERSION_MAJOR, MBFL_VERSION_MINOR, MBFL_VERSION_TEENY);
    1717         149 :                 php_info_print_table_row(2, "libmbfl version", tmp);
    1718             :         }
    1719             : #if HAVE_ONIG
    1720             :         {
    1721             :                 char tmp[256];
    1722         149 :                 snprintf(tmp, sizeof(tmp), "%d.%d.%d", ONIGURUMA_VERSION_MAJOR, ONIGURUMA_VERSION_MINOR, ONIGURUMA_VERSION_TEENY);
    1723         149 :                 php_info_print_table_row(2, "oniguruma version", tmp);
    1724             :         }
    1725             : #endif
    1726         149 :         php_info_print_table_end();
    1727             : 
    1728         149 :         php_info_print_table_start();
    1729         149 :         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         149 :         php_info_print_table_end();
    1731             : 
    1732             : #if HAVE_MBREGEX
    1733         149 :         PHP_MINFO(mb_regex)(ZEND_MODULE_INFO_FUNC_ARGS_PASSTHRU);
    1734             : #endif
    1735             : 
    1736         149 :         DISPLAY_INI_ENTRIES();
    1737         149 : }
    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\"", ZSTR_VAL(name));
    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         181 :         zend_long offset = 0;
    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             : 
    2270         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) {
    2271          16 :                 return;
    2272             :         }
    2273             : 
    2274         165 :         if (enc_name != NULL) {
    2275         124 :                 haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(enc_name);
    2276         124 :                 if (haystack.no_encoding == mbfl_no_encoding_invalid) {
    2277          20 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", enc_name);
    2278          20 :                         RETURN_FALSE;
    2279             :                 }
    2280             :         }
    2281             : 
    2282         145 :         if (offset < 0 || offset > mbfl_strlen(&haystack)) {
    2283          32 :                 php_error_docref(NULL, E_WARNING, "Offset not contained in string");
    2284          32 :                 RETURN_FALSE;
    2285             :         }
    2286         113 :         if (needle.len == 0) {
    2287           8 :                 php_error_docref(NULL, E_WARNING, "Empty delimiter");
    2288           8 :                 RETURN_FALSE;
    2289             :         }
    2290             : 
    2291         105 :         n = mbfl_strpos(&haystack, &needle, offset, reverse);
    2292         105 :         if (n >= 0) {
    2293          52 :                 RETVAL_LONG(n);
    2294             :         } else {
    2295          53 :                 switch (-n) {
    2296             :                 case 1:
    2297          53 :                         break;
    2298             :                 case 2:
    2299           0 :                         php_error_docref(NULL, E_WARNING, "Needle has not positive length");
    2300           0 :                         break;
    2301             :                 case 4:
    2302           0 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding or conversion error");
    2303           0 :                         break;
    2304             :                 case 8:
    2305           0 :                         php_error_docref(NULL, E_NOTICE, "Argument is empty");
    2306           0 :                         break;
    2307             :                 default:
    2308           0 :                         php_error_docref(NULL, E_WARNING, "Unknown error in mb_strpos");
    2309             :                         break;
    2310             :                 }
    2311          53 :                 RETVAL_FALSE;
    2312             :         }
    2313             : }
    2314             : /* }}} */
    2315             : 
    2316             : /* {{{ proto int mb_strrpos(string haystack, string needle [, int offset [, string encoding]])
    2317             :    Find position of last occurrence of a string within another */
    2318         121 : PHP_FUNCTION(mb_strrpos)
    2319             : {
    2320             :         int n;
    2321             :         mbfl_string haystack, needle;
    2322         121 :         char *enc_name = NULL;
    2323             :         size_t enc_name_len;
    2324         121 :         zval *zoffset = NULL;
    2325         121 :         long offset = 0, str_flg;
    2326         121 :         char *enc_name2 = NULL;
    2327             :         int enc_name_len2;
    2328             : 
    2329         121 :         mbfl_string_init(&haystack);
    2330         121 :         mbfl_string_init(&needle);
    2331         121 :         haystack.no_language = MBSTRG(language);
    2332         121 :         haystack.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2333         121 :         needle.no_language = MBSTRG(language);
    2334         121 :         needle.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2335             : 
    2336         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) {
    2337           5 :                 return;
    2338             :         }
    2339             : 
    2340         116 :         if (zoffset) {
    2341         226 :                 if (Z_TYPE_P(zoffset) == IS_STRING) {
    2342           6 :                         enc_name2     = Z_STRVAL_P(zoffset);
    2343           6 :                         enc_name_len2 = Z_STRLEN_P(zoffset);
    2344           6 :                         str_flg       = 1;
    2345             : 
    2346           6 :                         if (enc_name2 != NULL) {
    2347           6 :                                 switch (*enc_name2) {
    2348             :                                         case '0':
    2349             :                                         case '1':
    2350             :                                         case '2':
    2351             :                                         case '3':
    2352             :                                         case '4':
    2353             :                                         case '5':
    2354             :                                         case '6':
    2355             :                                         case '7':
    2356             :                                         case '8':
    2357             :                                         case '9':
    2358             :                                         case ' ':
    2359             :                                         case '-':
    2360             :                                         case '.':
    2361           0 :                                                 break;
    2362             :                                         default :
    2363           6 :                                                 str_flg = 0;
    2364             :                                                 break;
    2365             :                                 }
    2366             :                         }
    2367             : 
    2368           6 :                         if (str_flg) {
    2369           0 :                                 convert_to_long_ex(zoffset);
    2370           0 :                                 offset   = Z_LVAL_P(zoffset);
    2371             :                         } else {
    2372           6 :                                 enc_name     = enc_name2;
    2373           6 :                                 enc_name_len = enc_name_len2;
    2374             :                         }
    2375             :                 } else {
    2376         214 :                         convert_to_long_ex(zoffset);
    2377         107 :                         offset = Z_LVAL_P(zoffset);
    2378             :                 }
    2379             :         }
    2380             : 
    2381         116 :         if (enc_name != NULL) {
    2382         100 :                 haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(enc_name);
    2383         100 :                 if (haystack.no_encoding == mbfl_no_encoding_invalid) {
    2384          20 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", enc_name);
    2385          20 :                         RETURN_FALSE;
    2386             :                 }
    2387             :         }
    2388             : 
    2389          96 :         if (haystack.len <= 0) {
    2390           8 :                 RETURN_FALSE;
    2391             :         }
    2392          88 :         if (needle.len <= 0) {
    2393           8 :                 RETURN_FALSE;
    2394             :         }
    2395             : 
    2396             :         {
    2397          80 :                 int haystack_char_len = mbfl_strlen(&haystack);
    2398          93 :                 if ((offset > 0 && offset > haystack_char_len) ||
    2399          13 :                         (offset < 0 && -offset > haystack_char_len)) {
    2400           8 :                         php_error_docref(NULL, E_WARNING, "Offset is greater than the length of haystack string");
    2401           8 :                         RETURN_FALSE;
    2402             :                 }
    2403             :         }
    2404             : 
    2405          72 :         n = mbfl_strpos(&haystack, &needle, offset, 1);
    2406          72 :         if (n >= 0) {
    2407          42 :                 RETVAL_LONG(n);
    2408             :         } else {
    2409          30 :                 RETVAL_FALSE;
    2410             :         }
    2411             : }
    2412             : /* }}} */
    2413             : 
    2414             : /* {{{ proto int mb_stripos(string haystack, string needle [, int offset [, string encoding]])
    2415             :    Finds position of first occurrence of a string within another, case insensitive */
    2416         259 : PHP_FUNCTION(mb_stripos)
    2417             : {
    2418         259 :         int n = -1;
    2419         259 :         zend_long offset = 0;
    2420             :         mbfl_string haystack, needle;
    2421         259 :         const char *from_encoding = MBSTRG(current_internal_encoding)->mime_name;
    2422             :         size_t from_encoding_len;
    2423             : 
    2424         259 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|ls", (char **)&haystack.val, (int *)&haystack.len, (char **)&needle.val, (int *)&needle.len, &offset, &from_encoding, &from_encoding_len) == FAILURE) {
    2425          16 :                 return;
    2426             :         }
    2427         243 :         if (needle.len == 0) {
    2428           8 :                 php_error_docref(NULL, E_WARNING, "Empty delimiter");
    2429           8 :                 RETURN_FALSE;
    2430             :         }
    2431         235 :         n = php_mb_stripos(0, (char *)haystack.val, haystack.len, (char *)needle.val, needle.len, offset, from_encoding);
    2432             : 
    2433         235 :         if (n >= 0) {
    2434         116 :                 RETVAL_LONG(n);
    2435             :         } else {
    2436         119 :                 RETVAL_FALSE;
    2437             :         }
    2438             : }
    2439             : /* }}} */
    2440             : 
    2441             : /* {{{ proto int mb_strripos(string haystack, string needle [, int offset [, string encoding]])
    2442             :    Finds position of last occurrence of a string within another, case insensitive */
    2443         223 : PHP_FUNCTION(mb_strripos)
    2444             : {
    2445         223 :         int n = -1;
    2446         223 :         zend_long offset = 0;
    2447             :         mbfl_string haystack, needle;
    2448         223 :         const char *from_encoding = MBSTRG(current_internal_encoding)->mime_name;
    2449             :         size_t from_encoding_len;
    2450             : 
    2451         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) {
    2452          12 :                 return;
    2453             :         }
    2454             : 
    2455         211 :         n = php_mb_stripos(1, (char *)haystack.val, haystack.len, (char *)needle.val, needle.len, offset, from_encoding);
    2456             : 
    2457         211 :         if (n >= 0) {
    2458          83 :                 RETVAL_LONG(n);
    2459             :         } else {
    2460         128 :                 RETVAL_FALSE;
    2461             :         }
    2462             : }
    2463             : /* }}} */
    2464             : 
    2465             : /* {{{ proto string mb_strstr(string haystack, string needle[, bool part[, string encoding]])
    2466             :    Finds first occurrence of a string within another */
    2467         138 : PHP_FUNCTION(mb_strstr)
    2468             : {
    2469             :         int n, len, mblen;
    2470         138 :         mbfl_string haystack, needle, result, *ret = NULL;
    2471         138 :         char *enc_name = NULL;
    2472             :         size_t enc_name_len;
    2473         138 :         zend_bool part = 0;
    2474             : 
    2475         138 :         mbfl_string_init(&haystack);
    2476         138 :         mbfl_string_init(&needle);
    2477         138 :         haystack.no_language = MBSTRG(language);
    2478         138 :         haystack.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2479         138 :         needle.no_language = MBSTRG(language);
    2480         138 :         needle.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2481             : 
    2482         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) {
    2483          27 :                 return;
    2484             :         }
    2485             : 
    2486         111 :         if (enc_name != NULL) {
    2487          89 :                 haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(enc_name);
    2488          89 :                 if (haystack.no_encoding == mbfl_no_encoding_invalid) {
    2489          21 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", enc_name);
    2490          21 :                         RETURN_FALSE;
    2491             :                 }
    2492             :         }
    2493             : 
    2494          90 :         if (needle.len <= 0) {
    2495           8 :                 php_error_docref(NULL, E_WARNING, "Empty delimiter");
    2496           8 :                 RETURN_FALSE;
    2497             :         }
    2498          82 :         n = mbfl_strpos(&haystack, &needle, 0, 0);
    2499          82 :         if (n >= 0) {
    2500          44 :                 mblen = mbfl_strlen(&haystack);
    2501          44 :                 if (part) {
    2502          21 :                         ret = mbfl_substr(&haystack, &result, 0, n);
    2503          21 :                         if (ret != NULL) {
    2504             :                                 // TODO: avoid reallocation ???
    2505          42 :                                 RETVAL_STRINGL((char *)ret->val, ret->len);
    2506          21 :                                 efree(ret->val);
    2507             :                         } else {
    2508           0 :                                 RETVAL_FALSE;
    2509             :                         }
    2510             :                 } else {
    2511          23 :                         len = (mblen - n);
    2512          23 :                         ret = mbfl_substr(&haystack, &result, n, len);
    2513          23 :                         if (ret != NULL) {
    2514             :                                 // TODO: avoid reallocation ???
    2515          46 :                                 RETVAL_STRINGL((char *)ret->val, ret->len);
    2516          23 :                                 efree(ret->val);
    2517             :                         } else {
    2518           0 :                                 RETVAL_FALSE;
    2519             :                         }
    2520             :                 }
    2521             :         } else {
    2522          38 :                 RETVAL_FALSE;
    2523             :         }
    2524             : }
    2525             : /* }}} */
    2526             : 
    2527             : /* {{{ proto string mb_strrchr(string haystack, string needle[, bool part[, string encoding]])
    2528             :    Finds the last occurrence of a character in a string within another */
    2529         130 : PHP_FUNCTION(mb_strrchr)
    2530             : {
    2531             :         int n, len, mblen;
    2532         130 :         mbfl_string haystack, needle, result, *ret = NULL;
    2533         130 :         char *enc_name = NULL;
    2534             :         size_t enc_name_len;
    2535         130 :         zend_bool part = 0;
    2536             : 
    2537         130 :         mbfl_string_init(&haystack);
    2538         130 :         mbfl_string_init(&needle);
    2539         130 :         haystack.no_language = MBSTRG(language);
    2540         130 :         haystack.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2541         130 :         needle.no_language = MBSTRG(language);
    2542         130 :         needle.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2543             : 
    2544         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) {
    2545          27 :                 return;
    2546             :         }
    2547             : 
    2548         103 :         if (enc_name != NULL) {
    2549          87 :                 haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(enc_name);
    2550          87 :                 if (haystack.no_encoding == mbfl_no_encoding_invalid) {
    2551          21 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", enc_name);
    2552          21 :                         RETURN_FALSE;
    2553             :                 }
    2554             :         }
    2555             : 
    2556          82 :         if (haystack.len <= 0) {
    2557           8 :                 RETURN_FALSE;
    2558             :         }
    2559          74 :         if (needle.len <= 0) {
    2560           8 :                 RETURN_FALSE;
    2561             :         }
    2562          66 :         n = mbfl_strpos(&haystack, &needle, 0, 1);
    2563          66 :         if (n >= 0) {
    2564          36 :                 mblen = mbfl_strlen(&haystack);
    2565          36 :                 if (part) {
    2566          18 :                         ret = mbfl_substr(&haystack, &result, 0, n);
    2567          18 :                         if (ret != NULL) {
    2568             :                                 // TODO: avoid reallocation ???
    2569          36 :                                 RETVAL_STRINGL((char *)ret->val, ret->len);
    2570          18 :                                 efree(ret->val);
    2571             :                         } else {
    2572           0 :                                 RETVAL_FALSE;
    2573             :                         }
    2574             :                 } else {
    2575          18 :                         len = (mblen - n);
    2576          18 :                         ret = mbfl_substr(&haystack, &result, n, len);
    2577          18 :                         if (ret != NULL) {
    2578             :                                 // TODO: avoid reallocation ???
    2579          36 :                                 RETVAL_STRINGL((char *)ret->val, ret->len);
    2580          18 :                                 efree(ret->val);
    2581             :                         } else {
    2582           0 :                                 RETVAL_FALSE;
    2583             :                         }
    2584             :                 }
    2585             :         } else {
    2586          30 :                 RETVAL_FALSE;
    2587             :         }
    2588             : }
    2589             : /* }}} */
    2590             : 
    2591             : /* {{{ proto string mb_stristr(string haystack, string needle[, bool part[, string encoding]])
    2592             :    Finds first occurrence of a string within another, case insensitive */
    2593         132 : PHP_FUNCTION(mb_stristr)
    2594             : {
    2595         132 :         zend_bool part = 0;
    2596             :         size_t from_encoding_len, len, mblen;
    2597             :         int n;
    2598         132 :         mbfl_string haystack, needle, result, *ret = NULL;
    2599         132 :         const char *from_encoding = MBSTRG(current_internal_encoding)->mime_name;
    2600         132 :         mbfl_string_init(&haystack);
    2601         132 :         mbfl_string_init(&needle);
    2602         132 :         haystack.no_language = MBSTRG(language);
    2603         132 :         haystack.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2604         132 :         needle.no_language = MBSTRG(language);
    2605         132 :         needle.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2606             : 
    2607             : 
    2608         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) {
    2609          27 :                 return;
    2610             :         }
    2611             : 
    2612         105 :         if (!needle.len) {
    2613           8 :                 php_error_docref(NULL, E_WARNING, "Empty delimiter");
    2614           8 :                 RETURN_FALSE;
    2615             :         }
    2616             : 
    2617          97 :         haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(from_encoding);
    2618          97 :         if (haystack.no_encoding == mbfl_no_encoding_invalid) {
    2619          21 :                 php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", from_encoding);
    2620          21 :                 RETURN_FALSE;
    2621             :         }
    2622             : 
    2623          76 :         n = php_mb_stripos(0, (char *)haystack.val, haystack.len, (char *)needle.val, needle.len, 0, from_encoding);
    2624             : 
    2625          76 :         if (n <0) {
    2626          34 :                 RETURN_FALSE;
    2627             :         }
    2628             : 
    2629          42 :         mblen = mbfl_strlen(&haystack);
    2630             : 
    2631          42 :         if (part) {
    2632          22 :                 ret = mbfl_substr(&haystack, &result, 0, n);
    2633          22 :                 if (ret != NULL) {
    2634             :                         // TODO: avoid reallocation ???
    2635          44 :                         RETVAL_STRINGL((char *)ret->val, ret->len);
    2636          22 :                         efree(ret->val);
    2637             :                 } else {
    2638           0 :                         RETVAL_FALSE;
    2639             :                 }
    2640             :         } else {
    2641          20 :                 len = (mblen - n);
    2642          20 :                 ret = mbfl_substr(&haystack, &result, n, len);
    2643          20 :                 if (ret != NULL) {
    2644             :                         // TODO: avoid reallocaton ???
    2645          40 :                         RETVAL_STRINGL((char *)ret->val, ret->len);
    2646          20 :                         efree(ret->val);
    2647             :                 } else {
    2648           0 :                         RETVAL_FALSE;
    2649             :                 }
    2650             :         }
    2651             : }
    2652             : /* }}} */
    2653             : 
    2654             : /* {{{ proto string mb_strrichr(string haystack, string needle[, bool part[, string encoding]])
    2655             :    Finds the last occurrence of a character in a string within another, case insensitive */
    2656         132 : PHP_FUNCTION(mb_strrichr)
    2657             : {
    2658         132 :         zend_bool part = 0;
    2659             :         int n, len, mblen;
    2660             :         size_t from_encoding_len;
    2661         132 :         mbfl_string haystack, needle, result, *ret = NULL;
    2662         132 :         const char *from_encoding = MBSTRG(current_internal_encoding)->name;
    2663         132 :         mbfl_string_init(&haystack);
    2664         132 :         mbfl_string_init(&needle);
    2665         132 :         haystack.no_language = MBSTRG(language);
    2666         132 :         haystack.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2667         132 :         needle.no_language = MBSTRG(language);
    2668         132 :         needle.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2669             : 
    2670             : 
    2671         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) {
    2672          27 :                 return;
    2673             :         }
    2674             : 
    2675         105 :         haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(from_encoding);
    2676         105 :         if (haystack.no_encoding == mbfl_no_encoding_invalid) {
    2677          21 :                 php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", from_encoding);
    2678          21 :                 RETURN_FALSE;
    2679             :         }
    2680             : 
    2681          84 :         n = php_mb_stripos(1, (char *)haystack.val, haystack.len, (char *)needle.val, needle.len, 0, from_encoding);
    2682             : 
    2683          84 :         if (n <0) {
    2684          42 :                 RETURN_FALSE;
    2685             :         }
    2686             : 
    2687          42 :         mblen = mbfl_strlen(&haystack);
    2688             : 
    2689          42 :         if (part) {
    2690          22 :                 ret = mbfl_substr(&haystack, &result, 0, n);
    2691          22 :                 if (ret != NULL) {
    2692             :                         // TODO: avoid reallocation ???
    2693          44 :                         RETVAL_STRINGL((char *)ret->val, ret->len);
    2694          22 :                         efree(ret->val);
    2695             :                 } else {
    2696           0 :                         RETVAL_FALSE;
    2697             :                 }
    2698             :         } else {
    2699          20 :                 len = (mblen - n);
    2700          20 :                 ret = mbfl_substr(&haystack, &result, n, len);
    2701          20 :                 if (ret != NULL) {
    2702             :                         // TODO: avoid reallocation ???
    2703          40 :                         RETVAL_STRINGL((char *)ret->val, ret->len);
    2704          20 :                         efree(ret->val);
    2705             :                 } else {
    2706           0 :                         RETVAL_FALSE;
    2707             :                 }
    2708             :         }
    2709             : }
    2710             : /* }}} */
    2711             : 
    2712             : /* {{{ proto int mb_substr_count(string haystack, string needle [, string encoding])
    2713             :    Count the number of substring occurrences */
    2714         100 : PHP_FUNCTION(mb_substr_count)
    2715             : {
    2716             :         int n;
    2717             :         mbfl_string haystack, needle;
    2718         100 :         char *enc_name = NULL;
    2719             :         size_t enc_name_len;
    2720             : 
    2721         100 :         mbfl_string_init(&haystack);
    2722         100 :         mbfl_string_init(&needle);
    2723         100 :         haystack.no_language = MBSTRG(language);
    2724         100 :         haystack.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2725         100 :         needle.no_language = MBSTRG(language);
    2726         100 :         needle.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2727             : 
    2728         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) {
    2729           5 :                 return;
    2730             :         }
    2731             : 
    2732          95 :         if (enc_name != NULL) {
    2733          27 :                 haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(enc_name);
    2734          27 :                 if (haystack.no_encoding == mbfl_no_encoding_invalid) {
    2735          20 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", enc_name);
    2736          20 :                         RETURN_FALSE;
    2737             :                 }
    2738             :         }
    2739             : 
    2740          75 :         if (needle.len <= 0) {
    2741          10 :                 php_error_docref(NULL, E_WARNING, "Empty substring");
    2742          10 :                 RETURN_FALSE;
    2743             :         }
    2744             : 
    2745          65 :         n = mbfl_substr_count(&haystack, &needle);
    2746          65 :         if (n >= 0) {
    2747          65 :                 RETVAL_LONG(n);
    2748             :         } else {
    2749           0 :                 RETVAL_FALSE;
    2750             :         }
    2751             : }
    2752             : /* }}} */
    2753             : 
    2754             : /* {{{ proto string mb_substr(string str, int start [, int length [, string encoding]])
    2755             :    Returns part of a string */
    2756         300 : PHP_FUNCTION(mb_substr)
    2757             : {
    2758         300 :         char *str, *encoding = NULL;
    2759             :         zend_long from, len;
    2760             :         int mblen;
    2761             :         size_t str_len, encoding_len;
    2762         300 :         zend_bool len_is_null = 1;
    2763             :         mbfl_string string, result, *ret;
    2764             : 
    2765         300 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl|l!s", &str, &str_len, &from, &len, &len_is_null, &encoding, &encoding_len) == FAILURE) {
    2766           4 :                 return;
    2767             :         }
    2768             : 
    2769         296 :         mbfl_string_init(&string);
    2770         296 :         string.no_language = MBSTRG(language);
    2771         296 :         string.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2772             : 
    2773         296 :         if (encoding) {
    2774         219 :                 string.no_encoding = mbfl_name2no_encoding(encoding);
    2775         219 :                 if (string.no_encoding == mbfl_no_encoding_invalid) {
    2776          20 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", encoding);
    2777          20 :                         RETURN_FALSE;
    2778             :                 }
    2779             :         }
    2780             : 
    2781         276 :         string.val = (unsigned char *)str;
    2782         276 :         string.len = str_len;
    2783             : 
    2784         276 :         if (len_is_null) {
    2785           2 :                 len = str_len;
    2786             :         }
    2787             : 
    2788             :         /* measures length */
    2789         276 :         mblen = 0;
    2790         276 :         if (from < 0 || len < 0) {
    2791          49 :                 mblen = mbfl_strlen(&string);
    2792             :         }
    2793             : 
    2794             :         /* if "from" position is negative, count start position from the end
    2795             :          * of the string
    2796             :          */
    2797         276 :         if (from < 0) {
    2798          25 :                 from = mblen + from;
    2799          25 :                 if (from < 0) {
    2800          17 :                         from = 0;
    2801             :                 }
    2802             :         }
    2803             : 
    2804             :         /* if "length" position is negative, set it to the length
    2805             :          * needed to stop that many chars from the end of the string
    2806             :          */
    2807         276 :         if (len < 0) {
    2808          24 :                 len = (mblen - from) + len;
    2809          24 :                 if (len < 0) {
    2810          16 :                         len = 0;
    2811             :                 }
    2812             :         }
    2813             : 
    2814         276 :         if (((MBSTRG(func_overload) & MB_OVERLOAD_STRING) == MB_OVERLOAD_STRING)
    2815           0 :                 && (from >= mbfl_strlen(&string))) {
    2816           0 :                 RETURN_FALSE;
    2817             :         }
    2818             : 
    2819         276 :         ret = mbfl_substr(&string, &result, from, len);
    2820         276 :         if (NULL == ret) {
    2821           0 :                 RETURN_FALSE;
    2822             :         }
    2823             : 
    2824             :         // TODO: avoid reallocation ???
    2825         552 :         RETVAL_STRINGL((char *)ret->val, ret->len); /* the string is already strdup()'ed */
    2826         276 :         efree(ret->val);
    2827             : }
    2828             : /* }}} */
    2829             : 
    2830             : /* {{{ proto string mb_strcut(string str, int start [, int length [, string encoding]])
    2831             :    Returns part of a string */
    2832          18 : PHP_FUNCTION(mb_strcut)
    2833             : {
    2834          18 :         char *encoding = NULL;
    2835             :         zend_long from, len;
    2836             :         size_t encoding_len;
    2837          18 :         zend_bool len_is_null = 1;
    2838             :         mbfl_string string, result, *ret;
    2839             : 
    2840          18 :         mbfl_string_init(&string);
    2841          18 :         string.no_language = MBSTRG(language);
    2842          18 :         string.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2843             : 
    2844          18 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl|l!s", (char **)&string.val, (int **)&string.len, &from, &len, &len_is_null, &encoding, &encoding_len) == FAILURE) {
    2845           0 :                 return;
    2846             :         }
    2847             : 
    2848          18 :         if (encoding) {
    2849          11 :                 string.no_encoding = mbfl_name2no_encoding(encoding);
    2850          11 :                 if (string.no_encoding == mbfl_no_encoding_invalid) {
    2851           0 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", encoding);
    2852           0 :                         RETURN_FALSE;
    2853             :                 }
    2854             :         }
    2855             : 
    2856          18 :         if (len_is_null) {
    2857           1 :                 len = string.len;
    2858             :         }
    2859             : 
    2860             :         /* if "from" position is negative, count start position from the end
    2861             :          * of the string
    2862             :          */
    2863          18 :         if (from < 0) {
    2864           1 :                 from = string.len + from;
    2865           1 :                 if (from < 0) {
    2866           1 :                         from = 0;
    2867             :                 }
    2868             :         }
    2869             : 
    2870             :         /* if "length" position is negative, set it to the length
    2871             :          * needed to stop that many chars from the end of the string
    2872             :          */
    2873          18 :         if (len < 0) {
    2874           0 :                 len = (string.len - from) + len;
    2875           0 :                 if (len < 0) {
    2876           0 :                         len = 0;
    2877             :                 }
    2878             :         }
    2879             : 
    2880          18 :         if ((unsigned int)from > string.len) {
    2881           2 :                 RETURN_FALSE;
    2882             :         }
    2883             : 
    2884          16 :         ret = mbfl_strcut(&string, &result, from, len);
    2885          16 :         if (ret == NULL) {
    2886           0 :                 RETURN_FALSE;
    2887             :         }
    2888             : 
    2889             :         // TODO: avoid reallocation ???
    2890          32 :         RETVAL_STRINGL((char *)ret->val, ret->len); /* the string is already strdup()'ed */
    2891          16 :         efree(ret->val);
    2892             : }
    2893             : /* }}} */
    2894             : 
    2895             : /* {{{ proto int mb_strwidth(string str [, string encoding])
    2896             :    Gets terminal width of a string */
    2897        8257 : PHP_FUNCTION(mb_strwidth)
    2898             : {
    2899             :         int n;
    2900             :         mbfl_string string;
    2901        8257 :         char *enc_name = NULL;
    2902             :         size_t enc_name_len;
    2903             : 
    2904        8257 :         mbfl_string_init(&string);
    2905             : 
    2906        8257 :         string.no_language = MBSTRG(language);
    2907        8257 :         string.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2908             : 
    2909        8257 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s", (char **)&string.val, &string.len, &enc_name, &enc_name_len) == FAILURE) {
    2910           0 :                 return;
    2911             :         }
    2912             : 
    2913        8257 :         if (enc_name != NULL) {
    2914        8257 :                 string.no_encoding = mbfl_name2no_encoding(enc_name);
    2915        8257 :                 if (string.no_encoding == mbfl_no_encoding_invalid) {
    2916           0 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", enc_name);
    2917           0 :                         RETURN_FALSE;
    2918             :                 }
    2919             :         }
    2920             : 
    2921        8257 :         n = mbfl_strwidth(&string);
    2922        8257 :         if (n >= 0) {
    2923        8257 :                 RETVAL_LONG(n);
    2924             :         } else {
    2925           0 :                 RETVAL_FALSE;
    2926             :         }
    2927             : }
    2928             : /* }}} */
    2929             : 
    2930             : /* {{{ proto string mb_strimwidth(string str, int start, int width [, string trimmarker [, string encoding]])
    2931             :    Trim the string in terminal width */
    2932           9 : PHP_FUNCTION(mb_strimwidth)
    2933             : {
    2934           9 :         char *str, *trimmarker = NULL, *encoding = NULL;
    2935             :         zend_long from, width;
    2936             :         size_t str_len, trimmarker_len, encoding_len;
    2937             :         mbfl_string string, result, marker, *ret;
    2938             : 
    2939           9 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sll|ss", &str, &str_len, &from, &width, &trimmarker, &trimmarker_len, &encoding, &encoding_len) == FAILURE) {
    2940           0 :                 return;
    2941             :         }
    2942             : 
    2943           9 :         mbfl_string_init(&string);
    2944           9 :         mbfl_string_init(&marker);
    2945           9 :         string.no_language = MBSTRG(language);
    2946           9 :         string.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2947           9 :         marker.no_language = MBSTRG(language);
    2948           9 :         marker.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    2949           9 :         marker.val = NULL;
    2950           9 :         marker.len = 0;
    2951             : 
    2952           9 :         if (encoding) {
    2953           9 :                 string.no_encoding = marker.no_encoding = mbfl_name2no_encoding(encoding);
    2954           9 :                 if (string.no_encoding == mbfl_no_encoding_invalid) {
    2955           0 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", encoding);
    2956           0 :                         RETURN_FALSE;
    2957             :                 }
    2958             :         }
    2959             : 
    2960           9 :         string.val = (unsigned char *)str;
    2961           9 :         string.len = str_len;
    2962             : 
    2963           9 :         if (from < 0 || (size_t)from > str_len) {
    2964           3 :                 php_error_docref(NULL, E_WARNING, "Start position is out of range");
    2965           3 :                 RETURN_FALSE;
    2966             :         }
    2967             : 
    2968           6 :         if (width < 0) {
    2969           0 :                 php_error_docref(NULL, E_WARNING, "Width is negative value");
    2970           0 :                 RETURN_FALSE;
    2971             :         }
    2972             : 
    2973           6 :         if (trimmarker) {
    2974           6 :                 marker.val = (unsigned char *)trimmarker;
    2975           6 :                 marker.len = trimmarker_len;
    2976             :         }
    2977             : 
    2978           6 :         ret = mbfl_strimwidth(&string, &marker, &result, from, width);
    2979             : 
    2980           6 :         if (ret == NULL) {
    2981           0 :                 RETURN_FALSE;
    2982             :         }
    2983             :         // TODO: avoid reallocation ???
    2984          12 :         RETVAL_STRINGL((char *)ret->val, ret->len); /* the string is already strdup()'ed */
    2985           6 :         efree(ret->val);
    2986             : }
    2987             : /* }}} */
    2988             : 
    2989             : /* {{{ MBSTRING_API char *php_mb_convert_encoding() */
    2990       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)
    2991             : {
    2992             :         mbfl_string string, result, *ret;
    2993             :         const mbfl_encoding *from_encoding, *to_encoding;
    2994             :         mbfl_buffer_converter *convd;
    2995             :         size_t size;
    2996             :         const mbfl_encoding **list;
    2997       15068 :         char *output=NULL;
    2998             : 
    2999       15068 :         if (output_len) {
    3000       15068 :                 *output_len = 0;
    3001             :         }
    3002       15068 :         if (!input) {
    3003           0 :                 return NULL;
    3004             :         }
    3005             :         /* new encoding */
    3006       30115 :         if (_to_encoding && strlen(_to_encoding)) {
    3007       15060 :                 to_encoding = mbfl_name2encoding(_to_encoding);
    3008       15060 :                 if (!to_encoding) {
    3009          13 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", _to_encoding);
    3010          13 :                         return NULL;
    3011             :                 }
    3012             :         } else {
    3013           8 :                 to_encoding = MBSTRG(current_internal_encoding);
    3014             :         }
    3015             : 
    3016             :         /* initialize string */
    3017       15055 :         mbfl_string_init(&string);
    3018       15055 :         mbfl_string_init(&result);
    3019       15055 :         from_encoding = MBSTRG(current_internal_encoding);
    3020       15055 :         string.no_encoding = from_encoding->no_encoding;
    3021       15055 :         string.no_language = MBSTRG(language);
    3022       15055 :         string.val = (unsigned char *)input;
    3023       15055 :         string.len = length;
    3024             : 
    3025             :         /* pre-conversion encoding */
    3026       15055 :         if (_from_encodings) {
    3027       15042 :                 list = NULL;
    3028       15042 :                 size = 0;
    3029       15042 :                 php_mb_parse_encoding_list(_from_encodings, strlen(_from_encodings), &list, &size, 0);
    3030       15042 :                 if (size == 1) {
    3031       15033 :                         from_encoding = *list;
    3032       15033 :                         string.no_encoding = from_encoding->no_encoding;
    3033           9 :                 } else if (size > 1) {
    3034             :                         /* auto detect */
    3035           9 :                         from_encoding = mbfl_identify_encoding2(&string, list, size, MBSTRG(strict_detection));
    3036           9 :                         if (from_encoding) {
    3037           9 :                                 string.no_encoding = from_encoding->no_encoding;
    3038             :                         } else {
    3039           0 :                                 php_error_docref(NULL, E_WARNING, "Unable to detect character encoding");
    3040           0 :                                 from_encoding = &mbfl_encoding_pass;
    3041           0 :                                 to_encoding = from_encoding;
    3042           0 :                                 string.no_encoding = from_encoding->no_encoding;
    3043             :                         }
    3044             :                 } else {
    3045           0 :                         php_error_docref(NULL, E_WARNING, "Illegal character encoding specified");
    3046             :                 }
    3047       15042 :                 if (list != NULL) {
    3048       15042 :                         efree((void *)list);
    3049             :                 }
    3050             :         }
    3051             : 
    3052             :         /* initialize converter */
    3053       15055 :         convd = mbfl_buffer_converter_new2(from_encoding, to_encoding, string.len);
    3054       15055 :         if (convd == NULL) {
    3055           0 :                 php_error_docref(NULL, E_WARNING, "Unable to create character encoding converter");
    3056           0 :                 return NULL;
    3057             :         }
    3058       15055 :         mbfl_buffer_converter_illegal_mode(convd, MBSTRG(current_filter_illegal_mode));
    3059       15055 :         mbfl_buffer_converter_illegal_substchar(convd, MBSTRG(current_filter_illegal_substchar));
    3060             : 
    3061             :         /* do it */
    3062       15055 :         ret = mbfl_buffer_converter_feed_result(convd, &string, &result);
    3063       15055 :         if (ret) {
    3064       15055 :                 if (output_len) {
    3065       15055 :                         *output_len = ret->len;
    3066             :                 }
    3067       15055 :                 output = (char *)ret->val;
    3068             :         }
    3069             : 
    3070       15055 :         MBSTRG(illegalchars) += mbfl_buffer_illegalchars(convd);
    3071       15055 :         mbfl_buffer_converter_delete(convd);
    3072       15055 :         return output;
    3073             : }
    3074             : /* }}} */
    3075             : 
    3076             : /* {{{ proto string mb_convert_encoding(string str, string to-encoding [, mixed from-encoding])
    3077             :    Returns converted string in desired encoding */
    3078       12718 : PHP_FUNCTION(mb_convert_encoding)
    3079             : {
    3080             :         char *arg_str, *arg_new;
    3081             :         size_t str_len, new_len;
    3082       12718 :         zval *arg_old = NULL;
    3083             :         size_t size, l, n;
    3084       12718 :         char *_from_encodings = NULL, *ret, *s_free = NULL;
    3085             : 
    3086             :         zval *hash_entry;
    3087             :         HashTable *target_hash;
    3088             : 
    3089       12718 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|z", &arg_str, &str_len, &arg_new, &new_len, &arg_old) == FAILURE) {
    3090           2 :                 return;
    3091             :         }
    3092             : 
    3093       12716 :         if (arg_old) {
    3094       25404 :                 switch (Z_TYPE_P(arg_old)) {
    3095             :                         case IS_ARRAY:
    3096           3 :                                 target_hash = Z_ARRVAL_P(arg_old);
    3097           3 :                                 _from_encodings = NULL;
    3098             : 
    3099          27 :                                 ZEND_HASH_FOREACH_VAL(target_hash, hash_entry) {
    3100             : 
    3101          12 :                                         convert_to_string_ex(hash_entry);
    3102             : 
    3103          12 :                                         if ( _from_encodings) {
    3104           9 :                                                 l = strlen(_from_encodings);
    3105           9 :                                                 n = strlen(Z_STRVAL_P(hash_entry));
    3106           9 :                                                 _from_encodings = erealloc(_from_encodings, l+n+2);
    3107           9 :                                                 memcpy(_from_encodings + l, ",", 1);
    3108           9 :                                                 memcpy(_from_encodings + l + 1, Z_STRVAL_P(hash_entry), Z_STRLEN_P(hash_entry) + 1);
    3109             :                                         } else {
    3110           3 :                                                 _from_encodings = estrdup(Z_STRVAL_P(hash_entry));
    3111             :                                         }
    3112             :                                 } ZEND_HASH_FOREACH_END();
    3113             : 
    3114           3 :                                 if (_from_encodings != NULL && !strlen(_from_encodings)) {
    3115           0 :                                         efree(_from_encodings);
    3116           0 :                                         _from_encodings = NULL;
    3117             :                                 }
    3118           3 :                                 s_free = _from_encodings;
    3119           3 :                                 break;
    3120             :                         default:
    3121       25398 :                                 convert_to_string(arg_old);
    3122       12699 :                                 _from_encodings = Z_STRVAL_P(arg_old);
    3123             :                                 break;
    3124             :                         }
    3125             :         }
    3126             : 
    3127             :         /* new encoding */
    3128       12716 :         ret = php_mb_convert_encoding(arg_str, str_len, arg_new, _from_encodings, &size);
    3129       12716 :         if (ret != NULL) {
    3130             :                 // TODO: avoid reallocation ???
    3131       25406 :                 RETVAL_STRINGL(ret, size);              /* the string is already strdup()'ed */
    3132       12703 :                 efree(ret);
    3133             :         } else {
    3134          13 :                 RETVAL_FALSE;
    3135             :         }
    3136             : 
    3137       12716 :         if ( s_free) {
    3138           3 :                 efree(s_free);
    3139             :         }
    3140             : }
    3141             : /* }}} */
    3142             : 
    3143             : /* {{{ proto string mb_convert_case(string sourcestring, int mode [, string encoding])
    3144             :    Returns a case-folded version of sourcestring */
    3145           1 : PHP_FUNCTION(mb_convert_case)
    3146             : {
    3147           1 :         const char *from_encoding = MBSTRG(current_internal_encoding)->mime_name;
    3148             :         char *str;
    3149             :         size_t str_len, from_encoding_len;
    3150           1 :         zend_long case_mode = 0;
    3151             :         char *newstr;
    3152             :         size_t ret_len;
    3153             : 
    3154           1 :         RETVAL_FALSE;
    3155           1 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl|s!", &str, &str_len,
    3156             :                                 &case_mode, &from_encoding, &from_encoding_len) == FAILURE) {
    3157           0 :                 return;
    3158             :         }
    3159             : 
    3160           1 :         newstr = php_unicode_convert_case(case_mode, str, (size_t) str_len, &ret_len, from_encoding);
    3161             : 
    3162           1 :         if (newstr) {
    3163             :                 // TODO: avoid reallocation ???
    3164           2 :                 RETVAL_STRINGL(newstr, ret_len);
    3165           1 :                 efree(newstr);
    3166             :         }
    3167             : }
    3168             : /* }}} */
    3169             : 
    3170             : /* {{{ proto string mb_strtoupper(string sourcestring [, string encoding])
    3171             :  *  Returns a uppercased version of sourcestring
    3172             :  */
    3173          68 : PHP_FUNCTION(mb_strtoupper)
    3174             : {
    3175          68 :         const char *from_encoding = MBSTRG(current_internal_encoding)->mime_name;
    3176             :         char *str;
    3177             :         size_t str_len, from_encoding_len;
    3178             :         char *newstr;
    3179             :         size_t ret_len;
    3180             : 
    3181          68 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s!", &str, &str_len,
    3182             :                                 &from_encoding, &from_encoding_len) == FAILURE) {
    3183           4 :                 return;
    3184             :         }
    3185          64 :         newstr = php_unicode_convert_case(PHP_UNICODE_CASE_UPPER, str, (size_t) str_len, &ret_len, from_encoding);
    3186             : 
    3187          64 :         if (newstr) {
    3188             :                 // TODO: avoid reallocation ???
    3189          78 :                 RETVAL_STRINGL(newstr, ret_len);
    3190          39 :                 efree(newstr);
    3191          39 :                 return;
    3192             :         }
    3193          25 :         RETURN_FALSE;
    3194             : }
    3195             : /* }}} */
    3196             : 
    3197             : /* {{{ proto string mb_strtolower(string sourcestring [, string encoding])
    3198             :  *  Returns a lowercased version of sourcestring
    3199             :  */
    3200          65 : PHP_FUNCTION(mb_strtolower)
    3201             : {
    3202          65 :         const char *from_encoding = MBSTRG(current_internal_encoding)->mime_name;
    3203             :         char *str;
    3204             :         size_t str_len, from_encoding_len;
    3205             :         char *newstr;
    3206             :         size_t ret_len;
    3207             : 
    3208          65 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s!", &str, &str_len,
    3209             :                                 &from_encoding, &from_encoding_len) == FAILURE) {
    3210           4 :                 return;
    3211             :         }
    3212          61 :         newstr = php_unicode_convert_case(PHP_UNICODE_CASE_LOWER, str, (size_t) str_len, &ret_len, from_encoding);
    3213             : 
    3214          61 :         if (newstr) {
    3215             :                 // TODO: avoid reallocation ???
    3216          72 :                 RETVAL_STRINGL(newstr, ret_len);
    3217          36 :                 efree(newstr);
    3218          36 :                 return;
    3219             :         }
    3220          25 :         RETURN_FALSE;
    3221             : }
    3222             : /* }}} */
    3223             : 
    3224             : /* {{{ proto string mb_detect_encoding(string str [, mixed encoding_list [, bool strict]])
    3225             :    Encodings of the given string is returned (as a string) */
    3226          18 : PHP_FUNCTION(mb_detect_encoding)
    3227             : {
    3228             :         char *str;
    3229             :         size_t str_len;
    3230          18 :         zend_bool strict=0;
    3231          18 :         zval *encoding_list = NULL;
    3232             : 
    3233             :         mbfl_string string;
    3234             :         const mbfl_encoding *ret;
    3235             :         const mbfl_encoding **elist, **list;
    3236             :         size_t size;
    3237             : 
    3238          18 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|z!b", &str, &str_len, &encoding_list, &strict) == FAILURE) {
    3239           1 :                 return;
    3240             :         }
    3241             : 
    3242             :         /* make encoding list */
    3243          17 :         list = NULL;
    3244          17 :         size = 0;
    3245          17 :         if (encoding_list) {
    3246          28 :                 switch (Z_TYPE_P(encoding_list)) {
    3247             :                 case IS_ARRAY:
    3248           3 :                         if (FAILURE == php_mb_parse_encoding_array(encoding_list, &list, &size, 0)) {
    3249           0 :                                 if (list) {
    3250           0 :                                         efree(list);
    3251           0 :                                         list = NULL;
    3252           0 :                                         size = 0;
    3253             :                                 }
    3254             :                         }
    3255           3 :                         break;
    3256             :                 default:
    3257          22 :                         convert_to_string(encoding_list);
    3258          11 :                         if (FAILURE == php_mb_parse_encoding_list(Z_STRVAL_P(encoding_list), Z_STRLEN_P(encoding_list), &list, &size, 0)) {
    3259           0 :                                 if (list) {
    3260           0 :                                         efree(list);
    3261           0 :                                         list = NULL;
    3262           0 :                                         size = 0;
    3263             :                                 }
    3264             :                         }
    3265             :                         break;
    3266             :                 }
    3267          14 :                 if (size <= 0) {
    3268           1 :                         php_error_docref(NULL, E_WARNING, "Illegal argument");
    3269             :                 }
    3270             :         }
    3271             : 
    3272          17 :         if (ZEND_NUM_ARGS() < 3) {
    3273          13 :                 strict = (zend_bool)MBSTRG(strict_detection);
    3274             :         }
    3275             : 
    3276          30 :         if (size > 0 && list != NULL) {
    3277          13 :                 elist = list;
    3278             :         } else {
    3279           4 :                 elist = MBSTRG(current_detect_order_list);
    3280           4 :                 size = MBSTRG(current_detect_order_list_size);
    3281             :         }
    3282             : 
    3283          17 :         mbfl_string_init(&string);
    3284          17 :         string.no_language = MBSTRG(language);
    3285          17 :         string.val = (unsigned char *)str;
    3286          17 :         string.len = str_len;
    3287          17 :         ret = mbfl_identify_encoding2(&string, elist, size, strict);
    3288             : 
    3289          17 :         if (list != NULL) {
    3290          13 :                 efree((void *)list);
    3291             :         }
    3292             : 
    3293          17 :         if (ret == NULL) {
    3294           3 :                 RETURN_FALSE;
    3295             :         }
    3296             : 
    3297          28 :         RETVAL_STRING((char *)ret->name);
    3298             : }
    3299             : /* }}} */
    3300             : 
    3301             : /* {{{ proto mixed mb_list_encodings()
    3302             :    Returns an array of all supported entity encodings */
    3303           4 : PHP_FUNCTION(mb_list_encodings)
    3304             : {
    3305             :         const mbfl_encoding **encodings;
    3306             :         const mbfl_encoding *encoding;
    3307             :         int i;
    3308             : 
    3309           4 :         array_init(return_value);
    3310           4 :         i = 0;
    3311           4 :         encodings = mbfl_get_supported_encodings();
    3312         356 :         while ((encoding = encodings[i++]) != NULL) {
    3313         348 :                 add_next_index_string(return_value, (char *) encoding->name);
    3314             :         }
    3315           4 : }
    3316             : /* }}} */
    3317             : 
    3318             : /* {{{ proto array mb_encoding_aliases(string encoding)
    3319             :    Returns an array of the aliases of a given encoding name */
    3320           4 : PHP_FUNCTION(mb_encoding_aliases)
    3321             : {
    3322             :         const mbfl_encoding *encoding;
    3323           4 :         char *name = NULL;
    3324             :         size_t name_len;
    3325             : 
    3326           4 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
    3327           1 :                 return;
    3328             :         }
    3329             : 
    3330           3 :         encoding = mbfl_name2encoding(name);
    3331           3 :         if (!encoding) {
    3332           0 :                 php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", name);
    3333           0 :                 RETURN_FALSE;
    3334             :         }
    3335             : 
    3336           3 :         array_init(return_value);
    3337           3 :         if (encoding->aliases != NULL) {
    3338             :                 const char **alias;
    3339          14 :                 for (alias = *encoding->aliases; *alias; ++alias) {
    3340          12 :                         add_next_index_string(return_value, (char *)*alias);
    3341             :                 }
    3342             :         }
    3343             : }
    3344             : /* }}} */
    3345             : 
    3346             : /* {{{ proto string mb_encode_mimeheader(string str [, string charset [, string transfer-encoding [, string linefeed [, int indent]]]])
    3347             :    Converts the string to MIME "encoded-word" in the format of =?charset?(B|Q)?encoded_string?= */
    3348         341 : PHP_FUNCTION(mb_encode_mimeheader)
    3349             : {
    3350             :         enum mbfl_no_encoding charset, transenc;
    3351             :         mbfl_string  string, result, *ret;
    3352         341 :         char *charset_name = NULL;
    3353             :         size_t charset_name_len;
    3354         341 :         char *trans_enc_name = NULL;
    3355             :         size_t trans_enc_name_len;
    3356         341 :         char *linefeed = "\r\n";
    3357             :         size_t linefeed_len;
    3358         341 :         zend_long indent = 0;
    3359             : 
    3360         341 :         mbfl_string_init(&string);
    3361         341 :         string.no_language = MBSTRG(language);
    3362         341 :         string.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    3363             : 
    3364         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) {
    3365          11 :                 return;
    3366             :         }
    3367             : 
    3368         330 :         charset = mbfl_no_encoding_pass;
    3369         330 :         transenc = mbfl_no_encoding_base64;
    3370             : 
    3371         330 :         if (charset_name != NULL) {
    3372         330 :                 charset = mbfl_name2no_encoding(charset_name);
    3373         330 :                 if (charset == mbfl_no_encoding_invalid) {
    3374          19 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", charset_name);
    3375          19 :                         RETURN_FALSE;
    3376             :                 }
    3377             :         } else {
    3378           0 :                 const mbfl_language *lang = mbfl_no2language(MBSTRG(language));
    3379           0 :                 if (lang != NULL) {
    3380           0 :                         charset = lang->mail_charset;
    3381           0 :                         transenc = lang->mail_header_encoding;
    3382             :                 }
    3383             :         }
    3384             : 
    3385         311 :         if (trans_enc_name != NULL) {
    3386         490 :                 if (*trans_enc_name == 'B' || *trans_enc_name == 'b') {
    3387         179 :                         transenc = mbfl_no_encoding_base64;
    3388         132 :                 } else if (*trans_enc_name == 'Q' || *trans_enc_name == 'q') {
    3389         109 :                         transenc = mbfl_no_encoding_qprint;
    3390             :                 }
    3391             :         }
    3392             : 
    3393         311 :         mbfl_string_init(&result);
    3394         311 :         ret = mbfl_mime_header_encode(&string, &result, charset, transenc, linefeed, indent);
    3395         311 :         if (ret != NULL) {
    3396             :                 // TODO: avoid reallocation ???
    3397         622 :                 RETVAL_STRINGL((char *)ret->val, ret->len);       /* the string is already strdup()'ed */
    3398         311 :                 efree(ret->val);
    3399             :         } else {
    3400           0 :                 RETVAL_FALSE;
    3401             :         }
    3402             : }
    3403             : /* }}} */
    3404             : 
    3405             : /* {{{ proto string mb_decode_mimeheader(string string)
    3406             :    Decodes the MIME "encoded-word" in the string */
    3407          39 : PHP_FUNCTION(mb_decode_mimeheader)
    3408             : {
    3409             :         mbfl_string string, result, *ret;
    3410             : 
    3411          39 :         mbfl_string_init(&string);
    3412          39 :         string.no_language = MBSTRG(language);
    3413          39 :         string.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    3414             : 
    3415          39 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", (char **)&string.val, &string.len) == FAILURE) {
    3416           8 :                 return;
    3417             :         }
    3418             : 
    3419          31 :         mbfl_string_init(&result);
    3420          31 :         ret = mbfl_mime_header_decode(&string, &result, MBSTRG(current_internal_encoding)->no_encoding);
    3421          31 :         if (ret != NULL) {
    3422             :                 // TODO: avoid reallocation ???
    3423          62 :                 RETVAL_STRINGL((char *)ret->val, ret->len);       /* the string is already strdup()'ed */
    3424          31 :                 efree(ret->val);
    3425             :         } else {
    3426           0 :                 RETVAL_FALSE;
    3427             :         }
    3428             : }
    3429             : /* }}} */
    3430             : 
    3431             : /* {{{ proto string mb_convert_kana(string str [, string option] [, string encoding])
    3432             :    Conversion between full-width character and half-width character (Japanese) */
    3433          10 : PHP_FUNCTION(mb_convert_kana)
    3434             : {
    3435             :         int opt, i;
    3436             :         mbfl_string string, result, *ret;
    3437          10 :         char *optstr = NULL;
    3438             :         size_t optstr_len;
    3439          10 :         char *encname = NULL;
    3440             :         size_t encname_len;
    3441             : 
    3442          10 :         mbfl_string_init(&string);
    3443          10 :         string.no_language = MBSTRG(language);
    3444          10 :         string.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    3445             : 
    3446          10 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|ss", (char **)&string.val, &string.len, &optstr, &optstr_len, &encname, &encname_len) == FAILURE) {
    3447           0 :                 return;
    3448             :         }
    3449             : 
    3450             :         /* option */
    3451          10 :         if (optstr != NULL) {
    3452          10 :                 char *p = optstr;
    3453          10 :                 int n = optstr_len;
    3454          10 :                 i = 0;
    3455          10 :                 opt = 0;
    3456          60 :                 while (i < n) {
    3457          40 :                         i++;
    3458          40 :                         switch (*p++) {
    3459             :                         case 'A':
    3460           5 :                                 opt |= 0x1;
    3461           5 :                                 break;
    3462             :                         case 'a':
    3463           5 :                                 opt |= 0x10;
    3464           5 :                                 break;
    3465             :                         case 'R':
    3466           0 :                                 opt |= 0x2;
    3467           0 :                                 break;
    3468             :                         case 'r':
    3469           0 :                                 opt |= 0x20;
    3470           0 :                                 break;
    3471             :                         case 'N':
    3472           0 :                                 opt |= 0x4;
    3473           0 :                                 break;
    3474             :                         case 'n':
    3475           0 :                                 opt |= 0x40;
    3476           0 :                                 break;
    3477             :                         case 'S':
    3478           0 :                                 opt |= 0x8;
    3479           0 :                                 break;
    3480             :                         case 's':
    3481           0 :                                 opt |= 0x80;
    3482           0 :                                 break;
    3483             :                         case 'K':
    3484           5 :                                 opt |= 0x100;
    3485           5 :                                 break;
    3486             :                         case 'k':
    3487           5 :                                 opt |= 0x1000;
    3488           5 :                                 break;
    3489             :                         case 'H':
    3490           5 :                                 opt |= 0x200;
    3491           5 :                                 break;
    3492             :                         case 'h':
    3493           5 :                                 opt |= 0x2000;
    3494           5 :                                 break;
    3495             :                         case 'V':
    3496           0 :                                 opt |= 0x800;
    3497           0 :                                 break;
    3498             :                         case 'C':
    3499           0 :                                 opt |= 0x10000;
    3500           0 :                                 break;
    3501             :                         case 'c':
    3502           0 :                                 opt |= 0x20000;
    3503           0 :                                 break;
    3504             :                         case 'M':
    3505           0 :                                 opt |= 0x100000;
    3506           0 :                                 break;
    3507             :                         case 'm':
    3508           0 :                                 opt |= 0x200000;
    3509             :                                 break;
    3510             :                         }
    3511             :                 }
    3512             :         } else {
    3513           0 :                 opt = 0x900;
    3514             :         }
    3515             : 
    3516             :         /* encoding */
    3517          10 :         if (encname != NULL) {
    3518          10 :                 string.no_encoding = mbfl_name2no_encoding(encname);
    3519          10 :                 if (string.no_encoding == mbfl_no_encoding_invalid) {
    3520           0 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", encname);
    3521           0 :                         RETURN_FALSE;
    3522             :                 }
    3523             :         }
    3524             : 
    3525          10 :         ret = mbfl_ja_jp_hantozen(&string, &result, opt);
    3526          10 :         if (ret != NULL) {
    3527             :                 // TODO: avoid reallocation ???
    3528          20 :                 RETVAL_STRINGL((char *)ret->val, ret->len);               /* the string is already strdup()'ed */
    3529          10 :                 efree(ret->val);
    3530             :         } else {
    3531           0 :                 RETVAL_FALSE;
    3532             :         }
    3533             : }
    3534             : /* }}} */
    3535             : 
    3536             : #define PHP_MBSTR_STACK_BLOCK_SIZE 32
    3537             : 
    3538             : /* {{{ proto string mb_convert_variables(string to-encoding, mixed from-encoding, mixed vars [, ...])
    3539             :    Converts the string resource in variables to desired encoding */
    3540          17 : PHP_FUNCTION(mb_convert_variables)
    3541             : {
    3542             :         zval *args, *stack, *var, *hash_entry, *hash_entry_ptr, *zfrom_enc;
    3543             :         HashTable *target_hash;
    3544             :         mbfl_string string, result, *ret;
    3545             :         const mbfl_encoding *from_encoding, *to_encoding;
    3546             :         mbfl_encoding_detector *identd;
    3547             :         mbfl_buffer_converter *convd;
    3548             :         int n, argc, stack_level, stack_max;
    3549             :         size_t to_enc_len;
    3550             :         size_t elistsz;
    3551             :         const mbfl_encoding **elist;
    3552             :         char *to_enc;
    3553             :         void *ptmp;
    3554             : 
    3555          17 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz+", &to_enc, &to_enc_len, &zfrom_enc, &args, &argc) == FAILURE) {
    3556           0 :                 return;
    3557             :         }
    3558             : 
    3559             :         /* new encoding */
    3560          17 :         to_encoding = mbfl_name2encoding(to_enc);
    3561          17 :         if (!to_encoding) {
    3562           0 :                 php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", to_enc);
    3563           0 :                 RETURN_FALSE;
    3564             :         }
    3565             : 
    3566             :         /* initialize string */
    3567          17 :         mbfl_string_init(&string);
    3568          17 :         mbfl_string_init(&result);
    3569          17 :         from_encoding = MBSTRG(current_internal_encoding);
    3570          17 :         string.no_encoding = from_encoding->no_encoding;
    3571          17 :         string.no_language = MBSTRG(language);
    3572             : 
    3573             :         /* pre-conversion encoding */
    3574          17 :         elist = NULL;
    3575          17 :         elistsz = 0;
    3576          34 :         switch (Z_TYPE_P(zfrom_enc)) {
    3577             :                 case IS_ARRAY:
    3578           0 :                         php_mb_parse_encoding_array(zfrom_enc, &elist, &elistsz, 0);
    3579           0 :                         break;
    3580             :                 default:
    3581          34 :                         convert_to_string_ex(zfrom_enc);
    3582          17 :                         php_mb_parse_encoding_list(Z_STRVAL_P(zfrom_enc), Z_STRLEN_P(zfrom_enc), &elist, &elistsz, 0);
    3583             :                         break;
    3584             :         }
    3585             : 
    3586          17 :         if (elistsz <= 0) {
    3587           0 :                 from_encoding = &mbfl_encoding_pass;
    3588          17 :         } else if (elistsz == 1) {
    3589          11 :                 from_encoding = *elist;
    3590             :         } else {
    3591             :                 /* auto detect */
    3592           6 :                 from_encoding = NULL;
    3593           6 :                 stack_max = PHP_MBSTR_STACK_BLOCK_SIZE;
    3594           6 :                 stack = (zval *)safe_emalloc(stack_max, sizeof(zval), 0);
    3595           6 :                 stack_level = 0;
    3596           6 :                 identd = mbfl_encoding_detector_new2(elist, elistsz, MBSTRG(strict_detection));
    3597           6 :                 if (identd != NULL) {
    3598           6 :                         n = 0;
    3599          12 :                         while (n < argc || stack_level > 0) {
    3600           6 :                                 if (stack_level <= 0) {
    3601           6 :                                         var = &args[n++];
    3602           6 :                                         ZVAL_DEREF(var);
    3603          10 :                                         SEPARATE_ZVAL_NOREF(var);
    3604          10 :                                         if (Z_TYPE_P(var) == IS_ARRAY || Z_TYPE_P(var) == IS_OBJECT) {
    3605           6 :                                                 target_hash = HASH_OF(var);
    3606           4 :                                                 if (target_hash != NULL) {
    3607           4 :                                                         zend_hash_internal_pointer_reset(target_hash);
    3608             :                                                 }
    3609             :                                         }
    3610             :                                 } else {
    3611           0 :                                         stack_level--;
    3612           0 :                                         var = &stack[stack_level];
    3613             :                                 }
    3614          10 :                                 if (Z_TYPE_P(var) == IS_ARRAY || Z_TYPE_P(var) == IS_OBJECT) {
    3615           6 :                                         target_hash = HASH_OF(var);
    3616           4 :                                         if (target_hash != NULL) {
    3617           8 :                                                 while ((hash_entry = zend_hash_get_current_data(target_hash)) != NULL) {
    3618           4 :                                                         zend_hash_move_forward(target_hash);
    3619           4 :                                                         if (Z_TYPE_P(hash_entry) == IS_INDIRECT) {
    3620           2 :                                                                 hash_entry = Z_INDIRECT_P(hash_entry);
    3621             :                                                         }
    3622           4 :                                                         ZVAL_DEREF(hash_entry);
    3623           8 :                                                         if (Z_TYPE_P(hash_entry) == IS_ARRAY || Z_TYPE_P(hash_entry) == IS_OBJECT) {
    3624           0 :                                                                 if (stack_level >= stack_max) {
    3625           0 :                                                                         stack_max += PHP_MBSTR_STACK_BLOCK_SIZE;
    3626           0 :                                                                         ptmp = erealloc(stack, sizeof(zval) * stack_max);
    3627           0 :                                                                         stack = (zval *)ptmp;
    3628             :                                                                 }
    3629           0 :                                                                 ZVAL_COPY_VALUE(&stack[stack_level], var);
    3630           0 :                                                                 stack_level++;
    3631           0 :                                                                 var = hash_entry;
    3632           0 :                                                                 target_hash = HASH_OF(var);
    3633           0 :                                                                 if (target_hash != NULL) {
    3634           0 :                                                                         zend_hash_internal_pointer_reset(target_hash);
    3635           0 :                                                                         continue;
    3636             :                                                                 }
    3637           4 :                                                         } else if (Z_TYPE_P(hash_entry) == IS_STRING) {
    3638           4 :                                                                 string.val = (unsigned char *)Z_STRVAL_P(hash_entry);
    3639           4 :                                                                 string.len = Z_STRLEN_P(hash_entry);
    3640           4 :                                                                 if (mbfl_encoding_detector_feed(identd, &string)) {
    3641           4 :                                                                         goto detect_end;                /* complete detecting */
    3642             :                                                                 }
    3643             :                                                         }
    3644             :                                                 }
    3645             :                                         }
    3646           2 :                                 } else if (Z_TYPE_P(var) == IS_STRING) {
    3647           2 :                                         string.val = (unsigned char *)Z_STRVAL_P(var);
    3648           2 :                                         string.len = Z_STRLEN_P(var);
    3649           2 :                                         if (mbfl_encoding_detector_feed(identd, &string)) {
    3650           2 :                                                 goto detect_end;                /* complete detecting */
    3651             :                                         }
    3652             :                                 }
    3653             :                         }
    3654             : detect_end:
    3655           6 :                         from_encoding = mbfl_encoding_detector_judge2(identd);
    3656           6 :                         mbfl_encoding_detector_delete(identd);
    3657             :                 }
    3658           6 :                 efree(stack);
    3659             : 
    3660           6 :                 if (!from_encoding) {
    3661           0 :                         php_error_docref(NULL, E_WARNING, "Unable to detect encoding");
    3662           0 :                         from_encoding = &mbfl_encoding_pass;
    3663             :                 }
    3664             :         }
    3665          17 :         if (elist != NULL) {
    3666          17 :                 efree((void *)elist);
    3667             :         }
    3668             :         /* create converter */
    3669          17 :         convd = NULL;
    3670          17 :         if (from_encoding != &mbfl_encoding_pass) {
    3671          17 :                 convd = mbfl_buffer_converter_new2(from_encoding, to_encoding, 0);
    3672          17 :                 if (convd == NULL) {
    3673           0 :                         php_error_docref(NULL, E_WARNING, "Unable to create converter");
    3674           0 :                         RETURN_FALSE;
    3675             :                 }
    3676          17 :                 mbfl_buffer_converter_illegal_mode(convd, MBSTRG(current_filter_illegal_mode));
    3677          17 :                 mbfl_buffer_converter_illegal_substchar(convd, MBSTRG(current_filter_illegal_substchar));
    3678             :         }
    3679             : 
    3680             :         /* convert */
    3681          17 :         if (convd != NULL) {
    3682          17 :                 stack_max = PHP_MBSTR_STACK_BLOCK_SIZE;
    3683          17 :                 stack = (zval*)safe_emalloc(stack_max, sizeof(zval), 0);
    3684          17 :                 stack_level = 0;
    3685          17 :                 n = 0;
    3686          58 :                 while (n < argc || stack_level > 0) {
    3687          24 :                         if (stack_level <= 0) {
    3688          23 :                                 var = &args[n++];
    3689          23 :                                 ZVAL_DEREF(var);
    3690          39 :                                 SEPARATE_ZVAL_NOREF(var);
    3691          38 :                                 if (Z_TYPE_P(var) == IS_ARRAY || Z_TYPE_P(var) == IS_OBJECT) {
    3692          14 :                                         target_hash = HASH_OF(var);
    3693          11 :                                         if (target_hash != NULL) {
    3694          11 :                                                 zend_hash_internal_pointer_reset(target_hash);
    3695             :                                         }
    3696             :                                 }
    3697             :                         } else {
    3698           1 :                                 stack_level--;
    3699           1 :                                 var = &stack[stack_level];
    3700             :                         }
    3701          51 :                         if (Z_TYPE_P(var) == IS_ARRAY || Z_TYPE_P(var) == IS_OBJECT) {
    3702          15 :                                 target_hash = HASH_OF(var);
    3703          12 :                                 if (target_hash != NULL) {
    3704          48 :                                         while ((hash_entry_ptr = zend_hash_get_current_data(target_hash)) != NULL) {
    3705          24 :                                                 zend_hash_move_forward(target_hash);
    3706          24 :                                                 if (Z_TYPE_P(hash_entry_ptr) == IS_INDIRECT) {
    3707           9 :                                                         hash_entry_ptr = Z_INDIRECT_P(hash_entry_ptr);
    3708             :                                                 }
    3709          24 :                                                 hash_entry = hash_entry_ptr;
    3710          24 :                                                 ZVAL_DEREF(hash_entry);
    3711          47 :                                                 if (Z_TYPE_P(hash_entry) == IS_ARRAY || Z_TYPE_P(hash_entry) == IS_OBJECT) {
    3712           1 :                                                         if (stack_level >= stack_max) {
    3713           0 :                                                                 stack_max += PHP_MBSTR_STACK_BLOCK_SIZE;
    3714           0 :                                                                 ptmp = erealloc(stack, sizeof(zval) * stack_max);
    3715           0 :                                                                 stack = (zval *)ptmp;
    3716             :                                                         }
    3717           1 :                                                         ZVAL_COPY_VALUE(&stack[stack_level], var);
    3718           1 :                                                         stack_level++;
    3719           1 :                                                         var = hash_entry;
    3720           3 :                                                         SEPARATE_ZVAL(hash_entry);
    3721           1 :                                                         target_hash = HASH_OF(var);
    3722           1 :                                                         if (target_hash != NULL) {
    3723           1 :                                                                 zend_hash_internal_pointer_reset(target_hash);
    3724           1 :                                                                 continue;
    3725             :                                                         }
    3726          23 :                                                 } else if (Z_TYPE_P(hash_entry) == IS_STRING) {
    3727          23 :                                                         string.val = (unsigned char *)Z_STRVAL_P(hash_entry);
    3728          23 :                                                         string.len = Z_STRLEN_P(hash_entry);
    3729          23 :                                                         ret = mbfl_buffer_converter_feed_result(convd, &string, &result);
    3730          23 :                                                         if (ret != NULL) {
    3731          23 :                                                                 zval_ptr_dtor(hash_entry_ptr);
    3732             :                                                                 // TODO: avoid reallocation ???
    3733          46 :                                                                 ZVAL_STRINGL(hash_entry_ptr, (char *)ret->val, ret->len);
    3734          23 :                                                                 efree(ret->val);
    3735             :                                                         }
    3736             :                                                 }
    3737             :                                         }
    3738             :                                 }
    3739          12 :                         } else if (Z_TYPE_P(var) == IS_STRING) {
    3740          12 :                                 string.val = (unsigned char *)Z_STRVAL_P(var);
    3741          12 :                                 string.len = Z_STRLEN_P(var);
    3742          12 :                                 ret = mbfl_buffer_converter_feed_result(convd, &string, &result);
    3743          12 :                                 if (ret != NULL) {
    3744          12 :                                         zval_ptr_dtor(var);
    3745             :                                         // TODO: avoid reallocation ???
    3746          24 :                                         ZVAL_STRINGL(var, (char *)ret->val, ret->len);
    3747          12 :                                         efree(ret->val);
    3748             :                                 }
    3749             :                         }
    3750             :                 }
    3751          17 :                 efree(stack);
    3752             : 
    3753          17 :                 MBSTRG(illegalchars) += mbfl_buffer_illegalchars(convd);
    3754          17 :                 mbfl_buffer_converter_delete(convd);
    3755             :         }
    3756             : 
    3757          17 :         if (from_encoding) {
    3758          34 :                 RETURN_STRING(from_encoding->name);
    3759             :         } else {
    3760           0 :                 RETURN_FALSE;
    3761             :         }
    3762             : }
    3763             : /* }}} */
    3764             : 
    3765             : /* {{{ HTML numeric entity */
    3766             : /* {{{ static void php_mb_numericentity_exec() */
    3767             : static void
    3768          14 : php_mb_numericentity_exec(INTERNAL_FUNCTION_PARAMETERS, int type)
    3769             : {
    3770          14 :         char *str, *encoding = NULL;
    3771             :         size_t str_len, encoding_len;
    3772             :         zval *zconvmap, *hash_entry;
    3773             :         HashTable *target_hash;
    3774          14 :         int i, *convmap, *mapelm, mapsize=0;
    3775          14 :         zend_bool is_hex = 0;
    3776             :         mbfl_string string, result, *ret;
    3777             :         enum mbfl_no_encoding no_encoding;
    3778             : 
    3779          14 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz|sb", &str, &str_len, &zconvmap, &encoding, &encoding_len, &is_hex) == FAILURE) {
    3780           0 :                 return;
    3781             :         }
    3782             : 
    3783          14 :         mbfl_string_init(&string);
    3784          14 :         string.no_language = MBSTRG(language);
    3785          14 :         string.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    3786          14 :         string.val = (unsigned char *)str;
    3787          14 :         string.len = str_len;
    3788             : 
    3789             :         /* encoding */
    3790          14 :         if (encoding && encoding_len > 0) {
    3791          14 :                 no_encoding = mbfl_name2no_encoding(encoding);
    3792          14 :                 if (no_encoding == mbfl_no_encoding_invalid) {
    3793           0 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", encoding);
    3794           0 :                         RETURN_FALSE;
    3795             :                 } else {
    3796          14 :                         string.no_encoding = no_encoding;
    3797             :                 }
    3798             :         }
    3799             : 
    3800          14 :         if (type == 0 && is_hex) {
    3801           0 :                 type = 2; /* output in hex format */
    3802             :         }
    3803             : 
    3804             :         /* conversion map */
    3805          14 :         convmap = NULL;
    3806          28 :         if (Z_TYPE_P(zconvmap) == IS_ARRAY) {
    3807          14 :                 target_hash = Z_ARRVAL_P(zconvmap);
    3808          14 :                 i = zend_hash_num_elements(target_hash);
    3809          14 :                 if (i > 0) {
    3810          14 :                         convmap = (int *)safe_emalloc(i, sizeof(int), 0);
    3811          14 :                         mapelm = convmap;
    3812          14 :                         mapsize = 0;
    3813         126 :                         ZEND_HASH_FOREACH_VAL(target_hash, hash_entry) {
    3814          56 :                                 convert_to_long_ex(hash_entry);
    3815          56 :                                 *mapelm++ = Z_LVAL_P(hash_entry);
    3816          56 :                                 mapsize++;
    3817             :                         } ZEND_HASH_FOREACH_END();
    3818             :                 }
    3819             :         }
    3820          14 :         if (convmap == NULL) {
    3821           0 :                 RETURN_FALSE;
    3822             :         }
    3823          14 :         mapsize /= 4;
    3824             : 
    3825          14 :         ret = mbfl_html_numeric_entity(&string, &result, convmap, mapsize, type);
    3826          14 :         if (ret != NULL) {
    3827             :                 // TODO: avoid reallocation ???
    3828          28 :                 RETVAL_STRINGL((char *)ret->val, ret->len);
    3829          14 :                 efree(ret->val);
    3830             :         } else {
    3831           0 :                 RETVAL_FALSE;
    3832             :         }
    3833          14 :         efree((void *)convmap);
    3834             : }
    3835             : /* }}} */
    3836             : 
    3837             : /* {{{ proto string mb_encode_numericentity(string string, array convmap [, string encoding [, bool is_hex]])
    3838             :    Converts specified characters to HTML numeric entities */
    3839           3 : PHP_FUNCTION(mb_encode_numericentity)
    3840             : {
    3841           3 :         php_mb_numericentity_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    3842           3 : }
    3843             : /* }}} */
    3844             : 
    3845             : /* {{{ proto string mb_decode_numericentity(string string, array convmap [, string encoding])
    3846             :    Converts HTML numeric entities to character code */
    3847          11 : PHP_FUNCTION(mb_decode_numericentity)
    3848             : {
    3849          11 :         php_mb_numericentity_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    3850          11 : }
    3851             : /* }}} */
    3852             : /* }}} */
    3853             : 
    3854             : /* {{{ proto int mb_send_mail(string to, string subject, string message [, string additional_headers [, string additional_parameters]])
    3855             :  *  Sends an email message with MIME scheme
    3856             :  */
    3857             : 
    3858             : #define SKIP_LONG_HEADER_SEP_MBSTRING(str, pos)                                                                         \
    3859             :         if (str[pos] == '\r' && str[pos + 1] == '\n' && (str[pos + 2] == ' ' || str[pos + 2] == '\t')) {        \
    3860             :                 pos += 2;                                                                                       \
    3861             :                 while (str[pos + 1] == ' ' || str[pos + 1] == '\t') {                                                   \
    3862             :                         pos++;                                                                                  \
    3863             :                 }                                                                                               \
    3864             :                 continue;                                                                                       \
    3865             :         }
    3866             : 
    3867             : #define MAIL_ASCIIZ_CHECK_MBSTRING(str, len)                    \
    3868             :         pp = str;                                       \
    3869             :         ee = pp + len;                                  \
    3870             :         while ((pp = memchr(pp, '\0', (ee - pp)))) {    \
    3871             :                 *pp = ' ';                              \
    3872             :         }                                               \
    3873             : 
    3874           1 : static int _php_mbstr_parse_mail_headers(HashTable *ht, const char *str, size_t str_len)
    3875             : {
    3876             :         const char *ps;
    3877             :         size_t icnt;
    3878           1 :         int state = 0;
    3879           1 :         int crlf_state = -1;
    3880           1 :         char *token = NULL;
    3881           1 :         size_t token_pos = 0;
    3882             :         zend_string *fld_name, *fld_val;
    3883             : 
    3884           1 :         ps = str;
    3885           1 :         icnt = str_len;
    3886           1 :         fld_name = fld_val = NULL;
    3887             : 
    3888             :         /*
    3889             :          *             C o n t e n t - T y p e :   t e x t / h t m l \r\n
    3890             :          *             ^ ^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^^^^^^^^^ ^^^^
    3891             :          *      state  0            1           2          3
    3892             :          *
    3893             :          *             C o n t e n t - T y p e :   t e x t / h t m l \r\n
    3894             :          *             ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^
    3895             :          * crlf_state -1                       0                     1 -1
    3896             :          *
    3897             :          */
    3898             : 
    3899          19 :         while (icnt > 0) {
    3900          17 :                 switch (*ps) {
    3901             :                         case ':':
    3902           1 :                                 if (crlf_state == 1) {
    3903           0 :                                         token_pos++;
    3904             :                                 }
    3905             : 
    3906           2 :                                 if (state == 0 || state == 1) {
    3907           1 :                                         if(token && token_pos > 0) {
    3908           1 :                                                 fld_name = zend_string_init(token, token_pos, 0);
    3909             :                                         }
    3910           1 :                                         state = 2;
    3911             :                                 } else {
    3912           0 :                                         token_pos++;
    3913             :                                 }
    3914             : 
    3915           1 :                                 crlf_state = 0;
    3916           1 :                                 break;
    3917             : 
    3918             :                         case '\n':
    3919           0 :                                 if (crlf_state == -1) {
    3920           0 :                                         goto out;
    3921             :                                 }
    3922           0 :                                 crlf_state = -1;
    3923           0 :                                 break;
    3924             : 
    3925             :                         case '\r':
    3926           0 :                                 if (crlf_state == 1) {
    3927           0 :                                         token_pos++;
    3928             :                                 } else {
    3929           0 :                                         crlf_state = 1;
    3930             :                                 }
    3931           0 :                                 break;
    3932             : 
    3933             :                         case ' ': case '\t':
    3934           1 :                                 if (crlf_state == -1) {
    3935           0 :                                         if (state == 3) {
    3936             :                                                 /* continuing from the previous line */
    3937           0 :                                                 state = 4;
    3938             :                                         } else {
    3939             :                                                 /* simply skipping this new line */
    3940           0 :                                                 state = 5;
    3941             :                                         }
    3942             :                                 } else {
    3943           1 :                                         if (crlf_state == 1) {
    3944           0 :                                                 token_pos++;
    3945             :                                         }
    3946           1 :                                         if (state == 1 || state == 3) {
    3947           0 :                                                 token_pos++;
    3948             :                                         }
    3949             :                                 }
    3950           1 :                                 crlf_state = 0;
    3951           1 :                                 break;
    3952             : 
    3953             :                         default:
    3954          15 :                                 switch (state) {
    3955             :                                         case 0:
    3956           1 :                                                 token = (char*)ps;
    3957           1 :                                                 token_pos = 0;
    3958           1 :                                                 state = 1;
    3959           1 :                                                 break;
    3960             : 
    3961             :                                         case 2:
    3962           1 :                                                 if (crlf_state != -1) {
    3963           1 :                                                         token = (char*)ps;
    3964           1 :                                                         token_pos = 0;
    3965             : 
    3966           1 :                                                         state = 3;
    3967           1 :                                                         break;
    3968             :                                                 }
    3969             :                                                 /* break is missing intentionally */
    3970             : 
    3971             :                                         case 3:
    3972           2 :                                                 if (crlf_state == -1) {
    3973           0 :                                                         if(token && token_pos > 0) {
    3974           0 :                                                                 fld_val = zend_string_init(token, token_pos, 0);
    3975             :                                                         }
    3976             : 
    3977           0 :                                                         if (fld_name != NULL && fld_val != NULL) {
    3978             :                                                                 zval val;
    3979             :                                                                 /* FIXME: some locale free implementation is
    3980             :                                                                  * really required here,,, */
    3981           0 :                                                                 php_strtoupper(ZSTR_VAL(fld_name), ZSTR_LEN(fld_name));
    3982           0 :                                                                 ZVAL_STR(&val, fld_val);
    3983             : 
    3984           0 :                                                                 zend_hash_update(ht, fld_name, &val);
    3985             : 
    3986             :                                                                 zend_string_release(fld_name);
    3987             :                                                         }
    3988             : 
    3989           0 :                                                         fld_name = fld_val = NULL;
    3990           0 :                                                         token = (char*)ps;
    3991           0 :                                                         token_pos = 0;
    3992             : 
    3993           0 :                                                         state = 1;
    3994             :                                                 }
    3995           2 :                                                 break;
    3996             : 
    3997             :                                         case 4:
    3998           0 :                                                 token_pos++;
    3999           0 :                                                 state = 3;
    4000             :                                                 break;
    4001             :                                 }
    4002             : 
    4003          15 :                                 if (crlf_state == 1) {
    4004           0 :                                         token_pos++;
    4005             :                                 }
    4006             : 
    4007          15 :                                 token_pos++;
    4008             : 
    4009          15 :                                 crlf_state = 0;
    4010             :                                 break;
    4011             :                 }
    4012          17 :                 ps++, icnt--;
    4013             :         }
    4014             : out:
    4015           1 :         if (state == 2) {
    4016           0 :                 token = "";
    4017           0 :                 token_pos = 0;
    4018             : 
    4019           0 :                 state = 3;
    4020             :         }
    4021           1 :         if (state == 3) {
    4022           1 :                 if(token && token_pos > 0) {
    4023           1 :                         fld_val = zend_string_init(token, token_pos, 0);
    4024             :                 }
    4025           1 :                 if (fld_name != NULL && fld_val != NULL) {
    4026             :                         zval val;
    4027             :                         /* FIXME: some locale free implementation is
    4028             :                          * really required here,,, */
    4029           1 :                         php_strtoupper(ZSTR_VAL(fld_name), ZSTR_LEN(fld_name));
    4030           1 :                         ZVAL_STR(&val, fld_val);
    4031             : 
    4032           1 :                         zend_hash_update(ht, fld_name, &val);
    4033             : 
    4034             :                         zend_string_release(fld_name);
    4035             :                 }
    4036             :         }
    4037           1 :         return state;
    4038             : }
    4039             : 
    4040          15 : PHP_FUNCTION(mb_send_mail)
    4041             : {
    4042             :         int n;
    4043          15 :         char *to = NULL;
    4044             :         size_t to_len;
    4045          15 :         char *message = NULL;
    4046             :         size_t message_len;
    4047          15 :         char *headers = NULL;
    4048             :         size_t headers_len;
    4049          15 :         char *subject = NULL;
    4050          15 :         zend_string *extra_cmd = NULL;
    4051             :         size_t subject_len;
    4052             :         int i;
    4053          15 :         char *to_r = NULL;
    4054          15 :         char *force_extra_parameters = INI_STR("mail.force_extra_parameters");
    4055             :         struct {
    4056             :                 int cnt_type:1;
    4057             :                 int cnt_trans_enc:1;
    4058          15 :         } suppressed_hdrs = { 0, 0 };
    4059             : 
    4060          15 :         char *message_buf = NULL, *subject_buf = NULL, *p;
    4061             :         mbfl_string orig_str, conv_str;
    4062             :         mbfl_string *pstr;      /* pointer to mbfl string for return value */
    4063             :         enum mbfl_no_encoding
    4064             :                 tran_cs,        /* transfar text charset */
    4065             :                 head_enc,       /* header transfar encoding */
    4066             :                 body_enc;       /* body transfar encoding */
    4067             :         mbfl_memory_device device;      /* automatic allocateable buffer for additional header */
    4068             :         const mbfl_language *lang;
    4069          15 :         int err = 0;
    4070             :         HashTable ht_headers;
    4071             :         zval *s;
    4072             :         extern void mbfl_memory_device_unput(mbfl_memory_device *device);
    4073             :         char *pp, *ee;
    4074             : 
    4075             :         /* initialize */
    4076          15 :         mbfl_memory_device_init(&device, 0, 0);
    4077          15 :         mbfl_string_init(&orig_str);
    4078          15 :         mbfl_string_init(&conv_str);
    4079             : 
    4080             :         /* character-set, transfer-encoding */
    4081          15 :         tran_cs = mbfl_no_encoding_utf8;
    4082          15 :         head_enc = mbfl_no_encoding_base64;
    4083          15 :         body_enc = mbfl_no_encoding_base64;
    4084          15 :         lang = mbfl_no2language(MBSTRG(language));
    4085          15 :         if (lang != NULL) {
    4086          15 :                 tran_cs = lang->mail_charset;
    4087          15 :                 head_enc = lang->mail_header_encoding;
    4088          15 :                 body_enc = lang->mail_body_encoding;
    4089             :         }
    4090             : 
    4091          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) {
    4092           0 :                 return;
    4093             :         }
    4094             : 
    4095             :         /* ASCIIZ check */
    4096          15 :         MAIL_ASCIIZ_CHECK_MBSTRING(to, to_len);
    4097          15 :         MAIL_ASCIIZ_CHECK_MBSTRING(subject, subject_len);
    4098          15 :         MAIL_ASCIIZ_CHECK_MBSTRING(message, message_len);
    4099          15 :         if (headers) {
    4100           1 :                 MAIL_ASCIIZ_CHECK_MBSTRING(headers, headers_len);
    4101             :         }
    4102          15 :         if (extra_cmd) {
    4103           0 :                 MAIL_ASCIIZ_CHECK_MBSTRING(ZSTR_VAL(extra_cmd), ZSTR_LEN(extra_cmd));
    4104             :         }
    4105             : 
    4106          15 :         zend_hash_init(&ht_headers, 0, NULL, ZVAL_PTR_DTOR, 0);
    4107             : 
    4108          15 :         if (headers != NULL) {
    4109           1 :                 _php_mbstr_parse_mail_headers(&ht_headers, headers, headers_len);
    4110             :         }
    4111             : 
    4112          15 :         if ((s = zend_hash_str_find(&ht_headers, "CONTENT-TYPE", sizeof("CONTENT-TYPE") - 1))) {
    4113             :                 char *tmp;
    4114             :                 char *param_name;
    4115           0 :                 char *charset = NULL;
    4116             : 
    4117             :                 ZEND_ASSERT(Z_TYPE_P(s) == IS_STRING);
    4118           0 :                 p = strchr(Z_STRVAL_P(s), ';');
    4119             : 
    4120           0 :                 if (p != NULL) {
    4121             :                         /* skipping the padded spaces */
    4122             :                         do {
    4123           0 :                                 ++p;
    4124           0 :                         } while (*p == ' ' || *p == '\t');
    4125             : 
    4126           0 :                         if (*p != '\0') {
    4127           0 :                                 if ((param_name = php_strtok_r(p, "= ", &tmp)) != NULL) {
    4128           0 :                                         if (strcasecmp(param_name, "charset") == 0) {
    4129           0 :                                                 enum mbfl_no_encoding _tran_cs = tran_cs;
    4130             : 
    4131           0 :                                                 charset = php_strtok_r(NULL, "= \"", &tmp);
    4132           0 :                                                 if (charset != NULL) {
    4133           0 :                                                         _tran_cs = mbfl_name2no_encoding(charset);
    4134             :                                                 }
    4135             : 
    4136           0 :                                                 if (_tran_cs == mbfl_no_encoding_invalid) {
    4137           0 :                                                         php_error_docref(NULL, E_WARNING, "Unsupported charset \"%s\" - will be regarded as ascii", charset);
    4138           0 :                                                         _tran_cs = mbfl_no_encoding_ascii;
    4139             :                                                 }
    4140           0 :                                                 tran_cs = _tran_cs;
    4141             :                                         }
    4142             :                                 }
    4143             :                         }
    4144             :                 }
    4145           0 :                 suppressed_hdrs.cnt_type = 1;
    4146             :         }
    4147             : 
    4148          15 :         if ((s = zend_hash_str_find(&ht_headers, "CONTENT-TRANSFER-ENCODING", sizeof("CONTENT-TRANSFER-ENCODING") - 1))) {
    4149             :                 enum mbfl_no_encoding _body_enc;
    4150             : 
    4151             :                 ZEND_ASSERT(Z_TYPE_P(s) == IS_STRING);
    4152           0 :                 _body_enc = mbfl_name2no_encoding(Z_STRVAL_P(s));
    4153           0 :                 switch (_body_enc) {
    4154             :                         case mbfl_no_encoding_base64:
    4155             :                         case mbfl_no_encoding_7bit:
    4156             :                         case mbfl_no_encoding_8bit:
    4157           0 :                                 body_enc = _body_enc;
    4158           0 :                                 break;
    4159             : 
    4160             :                         default:
    4161           0 :                                 php_error_docref(NULL, E_WARNING, "Unsupported transfer encoding \"%s\" - will be regarded as 8bit", Z_STRVAL_P(s));
    4162           0 :                                 body_enc =      mbfl_no_encoding_8bit;
    4163             :                                 break;
    4164             :                 }
    4165           0 :                 suppressed_hdrs.cnt_trans_enc = 1;
    4166             :         }
    4167             : 
    4168             :         /* To: */
    4169          15 :         if (to != NULL) {
    4170          15 :                 if (to_len > 0) {
    4171          15 :                         to_r = estrndup(to, to_len);
    4172          15 :                         for (; to_len; to_len--) {
    4173          15 :                                 if (!isspace((unsigned char) to_r[to_len - 1])) {
    4174          15 :                                         break;
    4175             :                                 }
    4176           0 :                                 to_r[to_len - 1] = '\0';
    4177             :                         }
    4178         300 :                         for (i = 0; to_r[i]; i++) {
    4179         285 :                         if (iscntrl((unsigned char) to_r[i])) {
    4180             :                                 /* According to RFC 822, section 3.1.1 long headers may be separated into
    4181             :                                  * parts using CRLF followed at least one linear-white-space character ('\t' or ' ').
    4182             :                                  * To prevent these separators from being replaced with a space, we use the
    4183             :                                  * SKIP_LONG_HEADER_SEP_MBSTRING to skip over them.
    4184             :                                  */
    4185           0 :                                 SKIP_LONG_HEADER_SEP_MBSTRING(to_r, i);
    4186           0 :                                 to_r[i] = ' ';
    4187             :                         }
    4188             :                         }
    4189             :                 } else {
    4190           0 :                         to_r = to;
    4191             :                 }
    4192             :         } else {
    4193           0 :                 php_error_docref(NULL, E_WARNING, "Missing To: field");
    4194           0 :                 err = 1;
    4195             :         }
    4196             : 
    4197             :         /* Subject: */
    4198          15 :         if (subject != NULL) {
    4199          15 :                 orig_str.no_language = MBSTRG(language);
    4200          15 :                 orig_str.val = (unsigned char *)subject;
    4201          15 :                 orig_str.len = subject_len;
    4202          15 :                 orig_str.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    4203          15 :                 if (orig_str.no_encoding == mbfl_no_encoding_invalid || orig_str.no_encoding == mbfl_no_encoding_pass) {
    4204           1 :                         const mbfl_encoding *encoding = mbfl_identify_encoding2(&orig_str, MBSTRG(current_detect_order_list), MBSTRG(current_detect_order_list_size), MBSTRG(strict_detection));
    4205           1 :                         orig_str.no_encoding = encoding ? encoding->no_encoding: mbfl_no_encoding_invalid;
    4206             :                 }
    4207          15 :                 pstr = mbfl_mime_header_encode(&orig_str, &conv_str, tran_cs, head_enc, "\n", sizeof("Subject: [PHP-jp nnnnnnnn]"));
    4208          15 :                 if (pstr != NULL) {
    4209          15 :                         subject_buf = subject = (char *)pstr->val;
    4210             :                 }
    4211             :         } else {
    4212           0 :                 php_error_docref(NULL, E_WARNING, "Missing Subject: field");
    4213           0 :                 err = 1;
    4214             :         }
    4215             : 
    4216             :         /* message body */
    4217          15 :         if (message != NULL) {
    4218          15 :                 orig_str.no_language = MBSTRG(language);
    4219          15 :                 orig_str.val = (unsigned char *)message;
    4220          15 :                 orig_str.len = (unsigned int)message_len;
    4221          15 :                 orig_str.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    4222             : 
    4223          15 :                 if (orig_str.no_encoding == mbfl_no_encoding_invalid || orig_str.no_encoding == mbfl_no_encoding_pass) {
    4224           1 :                         const mbfl_encoding *encoding = mbfl_identify_encoding2(&orig_str, MBSTRG(current_detect_order_list), MBSTRG(current_detect_order_list_size), MBSTRG(strict_detection));
    4225           1 :                         orig_str.no_encoding = encoding ? encoding->no_encoding: mbfl_no_encoding_invalid;
    4226             :                 }
    4227             : 
    4228          15 :                 pstr = NULL;
    4229             :                 {
    4230             :                         mbfl_string tmpstr;
    4231             : 
    4232          15 :                         if (mbfl_convert_encoding(&orig_str, &tmpstr, tran_cs) != NULL) {
    4233          15 :                                 tmpstr.no_encoding=mbfl_no_encoding_8bit;
    4234          15 :                                 pstr = mbfl_convert_encoding(&tmpstr, &conv_str, body_enc);
    4235          15 :                                 efree(tmpstr.val);
    4236             :                         }
    4237             :                 }
    4238          15 :                 if (pstr != NULL) {
    4239          15 :                         message_buf = message = (char *)pstr->val;
    4240             :                 }
    4241             :         } else {
    4242             :                 /* this is not really an error, so it is allowed. */
    4243           0 :                 php_error_docref(NULL, E_WARNING, "Empty message body");
    4244           0 :                 message = NULL;
    4245             :         }
    4246             : 
    4247             :         /* other headers */
    4248             : #define PHP_MBSTR_MAIL_MIME_HEADER1 "MIME-Version: 1.0"
    4249             : #define PHP_MBSTR_MAIL_MIME_HEADER2 "Content-Type: text/plain"
    4250             : #define PHP_MBSTR_MAIL_MIME_HEADER3 "; charset="
    4251             : #define PHP_MBSTR_MAIL_MIME_HEADER4 "Content-Transfer-Encoding: "
    4252          15 :         if (headers != NULL) {
    4253           1 :                 p = headers;
    4254           1 :                 n = headers_len;
    4255           1 :                 mbfl_memory_device_strncat(&device, p, n);
    4256           1 :                 if (n > 0 && p[n - 1] != '\n') {
    4257           1 :                         mbfl_memory_device_strncat(&device, "\n", 1);
    4258             :                 }
    4259             :         }
    4260             : 
    4261          15 :         if (!zend_hash_str_exists(&ht_headers, "MIME-VERSION", sizeof("MIME-VERSION") - 1)) {
    4262          14 :                 mbfl_memory_device_strncat(&device, PHP_MBSTR_MAIL_MIME_HEADER1, sizeof(PHP_MBSTR_MAIL_MIME_HEADER1) - 1);
    4263          14 :                 mbfl_memory_device_strncat(&device, "\n", 1);
    4264             :         }
    4265             : 
    4266          15 :         if (!suppressed_hdrs.cnt_type) {
    4267          15 :                 mbfl_memory_device_strncat(&device, PHP_MBSTR_MAIL_MIME_HEADER2, sizeof(PHP_MBSTR_MAIL_MIME_HEADER2) - 1);
    4268             : 
    4269          15 :                 p = (char *)mbfl_no2preferred_mime_name(tran_cs);
    4270          15 :                 if (p != NULL) {
    4271          15 :                         mbfl_memory_device_strncat(&device, PHP_MBSTR_MAIL_MIME_HEADER3, sizeof(PHP_MBSTR_MAIL_MIME_HEADER3) - 1);
    4272          15 :                         mbfl_memory_device_strcat(&device, p);
    4273             :                 }
    4274          15 :                 mbfl_memory_device_strncat(&device, "\n", 1);
    4275             :         }
    4276          15 :         if (!suppressed_hdrs.cnt_trans_enc) {
    4277          15 :                 mbfl_memory_device_strncat(&device, PHP_MBSTR_MAIL_MIME_HEADER4, sizeof(PHP_MBSTR_MAIL_MIME_HEADER4) - 1);
    4278          15 :                 p = (char *)mbfl_no2preferred_mime_name(body_enc);
    4279          15 :                 if (p == NULL) {
    4280           0 :                         p = "7bit";
    4281             :                 }
    4282          15 :                 mbfl_memory_device_strcat(&device, p);
    4283          15 :                 mbfl_memory_device_strncat(&device, "\n", 1);
    4284             :         }
    4285             : 
    4286          15 :         mbfl_memory_device_unput(&device);
    4287          15 :         mbfl_memory_device_output('\0', &device);
    4288          15 :         headers = (char *)device.buffer;
    4289             : 
    4290          15 :         if (force_extra_parameters) {
    4291           0 :                 extra_cmd = php_escape_shell_cmd(force_extra_parameters);
    4292          15 :         } else if (extra_cmd) {
    4293           0 :                 extra_cmd = php_escape_shell_cmd(ZSTR_VAL(extra_cmd));
    4294             :         }
    4295             : 
    4296          30 :         if (!err && php_mail(to_r, subject, message, headers, extra_cmd ? ZSTR_VAL(extra_cmd) : NULL)) {
    4297          15 :                 RETVAL_TRUE;
    4298             :         } else {
    4299           0 :                 RETVAL_FALSE;
    4300             :         }
    4301             : 
    4302          15 :         if (extra_cmd) {
    4303           0 :                 zend_string_release(extra_cmd);
    4304             :         }
    4305             : 
    4306          15 :         if (to_r != to) {
    4307          15 :                 efree(to_r);
    4308             :         }
    4309          15 :         if (subject_buf) {
    4310          15 :                 efree((void *)subject_buf);
    4311             :         }
    4312          15 :         if (message_buf) {
    4313          15 :                 efree((void *)message_buf);
    4314             :         }
    4315          15 :         mbfl_memory_device_clear(&device);
    4316          15 :         zend_hash_destroy(&ht_headers);
    4317             : }
    4318             : 
    4319             : #undef SKIP_LONG_HEADER_SEP_MBSTRING
    4320             : #undef MAIL_ASCIIZ_CHECK_MBSTRING
    4321             : #undef PHP_MBSTR_MAIL_MIME_HEADER1
    4322             : #undef PHP_MBSTR_MAIL_MIME_HEADER2
    4323             : #undef PHP_MBSTR_MAIL_MIME_HEADER3
    4324             : #undef PHP_MBSTR_MAIL_MIME_HEADER4
    4325             : /* }}} */
    4326             : 
    4327             : /* {{{ proto mixed mb_get_info([string type])
    4328             :    Returns the current settings of mbstring */
    4329          16 : PHP_FUNCTION(mb_get_info)
    4330             : {
    4331          16 :         char *typ = NULL;
    4332             :         size_t typ_len;
    4333             :         size_t n;
    4334             :         char *name;
    4335             :         const struct mb_overload_def *over_func;
    4336             :         zval row1, row2;
    4337          16 :         const mbfl_language *lang = mbfl_no2language(MBSTRG(language));
    4338             :         const mbfl_encoding **entry;
    4339             : 
    4340          16 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &typ, &typ_len) == FAILURE) {
    4341           0 :                 return;
    4342             :         }
    4343             : 
    4344          17 :         if (!typ || !strcasecmp("all", typ)) {
    4345           1 :                 array_init(return_value);
    4346           1 :                 if (MBSTRG(current_internal_encoding)) {
    4347           1 :                         add_assoc_string(return_value, "internal_encoding", (char *)MBSTRG(current_internal_encoding)->name);
    4348             :                 }
    4349           1 :                 if (MBSTRG(http_input_identify)) {
    4350           1 :                         add_assoc_string(return_value, "http_input", (char *)MBSTRG(http_input_identify)->name);
    4351             :                 }
    4352           1 :                 if (MBSTRG(current_http_output_encoding)) {
    4353           1 :                         add_assoc_string(return_value, "http_output", (char *)MBSTRG(current_http_output_encoding)->name);
    4354             :                 }
    4355           1 :                 if ((name = (char *)zend_ini_string("mbstring.http_output_conv_mimetypes", sizeof("mbstring.http_output_conv_mimetypes") - 1, 0)) != NULL) {
    4356           1 :                         add_assoc_string(return_value, "http_output_conv_mimetypes", name);
    4357             :                 }
    4358           1 :                 add_assoc_long(return_value, "func_overload", MBSTRG(func_overload));
    4359           1 :                 if (MBSTRG(func_overload)){
    4360           1 :                         over_func = &(mb_ovld[0]);
    4361           1 :                         array_init(&row1);
    4362          15 :                         while (over_func->type > 0) {
    4363          13 :                                 if ((MBSTRG(func_overload) & over_func->type) == over_func->type ) {
    4364          12 :                                         add_assoc_string(&row1, over_func->orig_func, over_func->ovld_func);
    4365             :                                 }
    4366          13 :                                 over_func++;
    4367             :                         }
    4368           1 :                         add_assoc_zval(return_value, "func_overload_list", &row1);
    4369             :                 } else {
    4370           0 :                         add_assoc_string(return_value, "func_overload_list", "no overload");
    4371             :                 }
    4372           1 :                 if (lang != NULL) {
    4373           1 :                         if ((name = (char *)mbfl_no_encoding2name(lang->mail_charset)) != NULL) {
    4374           1 :                                 add_assoc_string(return_value, "mail_charset", name);
    4375             :                         }
    4376           1 :                         if ((name = (char *)mbfl_no_encoding2name(lang->mail_header_encoding)) != NULL) {
    4377           1 :                                 add_assoc_string(return_value, "mail_header_encoding", name);
    4378             :                         }
    4379           1 :                         if ((name = (char *)mbfl_no_encoding2name(lang->mail_body_encoding)) != NULL) {
    4380           1 :                                 add_assoc_string(return_value, "mail_body_encoding", name);
    4381             :                         }
    4382             :                 }
    4383           1 :                 add_assoc_long(return_value, "illegal_chars", MBSTRG(illegalchars));
    4384           1 :                 if (MBSTRG(encoding_translation)) {
    4385           1 :                         add_assoc_string(return_value, "encoding_translation", "On");
    4386             :                 } else {
    4387           0 :                         add_assoc_string(return_value, "encoding_translation", "Off");
    4388             :                 }
    4389           1 :                 if ((name = (char *)mbfl_no_language2name(MBSTRG(language))) != NULL) {
    4390           1 :                         add_assoc_string(return_value, "language", name);
    4391             :                 }
    4392           1 :                 n = MBSTRG(current_detect_order_list_size);
    4393           1 :                 entry = MBSTRG(current_detect_order_list);
    4394           1 :                 if (n > 0) {
    4395             :                         size_t i;
    4396           1 :                         array_init(&row2);
    4397           5 :                         for (i = 0; i < n; i++) {
    4398           4 :                                 add_next_index_string(&row2, (*entry)->name);
    4399           4 :                                 entry++;
    4400             :                         }
    4401           1 :                         add_assoc_zval(return_value, "detect_order", &row2);
    4402             :                 }
    4403           1 :                 if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE) {
    4404           0 :                         add_assoc_string(return_value, "substitute_character", "none");
    4405           1 :                 } else if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_LONG) {
    4406           0 :                         add_assoc_string(return_value, "substitute_character", "long");
    4407           1 :                 } else if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_ENTITY) {
    4408           0 :                         add_assoc_string(return_value, "substitute_character", "entity");
    4409             :                 } else {
    4410           1 :                         add_assoc_long(return_value, "substitute_character", MBSTRG(current_filter_illegal_substchar));
    4411             :                 }
    4412           1 :                 if (MBSTRG(strict_detection)) {
    4413           1 :                         add_assoc_string(return_value, "strict_detection", "On");
    4414             :                 } else {
    4415           0 :                         add_assoc_string(return_value, "strict_detection", "Off");
    4416             :                 }
    4417          15 :         } else if (!strcasecmp("internal_encoding", typ)) {
    4418           1 :                 if (MBSTRG(current_internal_encoding)) {
    4419           2 :                         RETVAL_STRING((char *)MBSTRG(current_internal_encoding)->name);
    4420             :                 }
    4421          14 :         } else if (!strcasecmp("http_input", typ)) {
    4422           1 :                 if (MBSTRG(http_input_identify)) {
    4423           2 :                         RETVAL_STRING((char *)MBSTRG(http_input_identify)->name);
    4424             :                 }
    4425          13 :         } else if (!strcasecmp("http_output", typ)) {
    4426           1 :                 if (MBSTRG(current_http_output_encoding)) {
    4427           2 :                         RETVAL_STRING((char *)MBSTRG(current_http_output_encoding)->name);
    4428             :                 }
    4429          12 :         } else if (!strcasecmp("http_output_conv_mimetypes", typ)) {
    4430           1 :                 if ((name = (char *)zend_ini_string("mbstring.http_output_conv_mimetypes", sizeof("mbstring.http_output_conv_mimetypes") - 1, 0)) != NULL) {
    4431           2 :                         RETVAL_STRING(name);
    4432             :                 }
    4433          11 :         } else if (!strcasecmp("func_overload", typ)) {
    4434           1 :                 RETVAL_LONG(MBSTRG(func_overload));
    4435          10 :         } else if (!strcasecmp("func_overload_list", typ)) {
    4436           1 :                 if (MBSTRG(func_overload)){
    4437           1 :                                 over_func = &(mb_ovld[0]);
    4438           1 :                                 array_init(return_value);
    4439          15 :                                 while (over_func->type > 0) {
    4440          13 :                                         if ((MBSTRG(func_overload) & over_func->type) == over_func->type ) {
    4441          12 :                                                 add_assoc_string(return_value, over_func->orig_func, over_func->ovld_func);
    4442             :                                         }
    4443          13 :                                         over_func++;
    4444             :                                 }
    4445             :                 } else {
    4446           0 :                         RETVAL_STRING("no overload");
    4447             :                 }
    4448           9 :         } else if (!strcasecmp("mail_charset", typ)) {
    4449           1 :                 if (lang != NULL && (name = (char *)mbfl_no_encoding2name(lang->mail_charset)) != NULL) {
    4450           2 :                         RETVAL_STRING(name);
    4451             :                 }
    4452           8 :         } else if (!strcasecmp("mail_header_encoding", typ)) {
    4453           1 :                 if (lang != NULL && (name = (char *)mbfl_no_encoding2name(lang->mail_header_encoding)) != NULL) {
    4454           2 :                         RETVAL_STRING(name);
    4455             :                 }
    4456           7 :         } else if (!strcasecmp("mail_body_encoding", typ)) {
    4457           1 :                 if (lang != NULL && (name = (char *)mbfl_no_encoding2name(lang->mail_body_encoding)) != NULL) {
    4458           2 :                         RETVAL_STRING(name);
    4459             :                 }
    4460           6 :         } else if (!strcasecmp("illegal_chars", typ)) {
    4461           1 :                 RETVAL_LONG(MBSTRG(illegalchars));
    4462           5 :         } else if (!strcasecmp("encoding_translation", typ)) {
    4463           1 :                 if (MBSTRG(encoding_translation)) {
    4464           2 :                         RETVAL_STRING("On");
    4465             :                 } else {
    4466           0 :                         RETVAL_STRING("Off");
    4467             :                 }
    4468           4 :         } else if (!strcasecmp("language", typ)) {
    4469           1 :                 if ((name = (char *)mbfl_no_language2name(MBSTRG(language))) != NULL) {
    4470           2 :                         RETVAL_STRING(name);
    4471             :                 }
    4472           3 :         } else if (!strcasecmp("detect_order", typ)) {
    4473           1 :                 n = MBSTRG(current_detect_order_list_size);
    4474           1 :                 entry = MBSTRG(current_detect_order_list);
    4475           1 :                 if (n > 0) {
    4476             :                         size_t i;
    4477           1 :                         array_init(return_value);
    4478           5 :                         for (i = 0; i < n; i++) {
    4479           4 :                                 add_next_index_string(return_value, (*entry)->name);
    4480           4 :                                 entry++;
    4481             :                         }
    4482             :                 }
    4483           2 :         } else if (!strcasecmp("substitute_character", typ)) {
    4484           1 :                 if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE) {
    4485           0 :                         RETVAL_STRING("none");
    4486           1 :                 } else if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_LONG) {
    4487           0 :                         RETVAL_STRING("long");
    4488           1 :                 } else if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_ENTITY) {
    4489           0 :                         RETVAL_STRING("entity");
    4490             :                 } else {
    4491           1 :                         RETVAL_LONG(MBSTRG(current_filter_illegal_substchar));
    4492             :                 }
    4493           1 :         } else if (!strcasecmp("strict_detection", typ)) {
    4494           1 :                 if (MBSTRG(strict_detection)) {
    4495           2 :                         RETVAL_STRING("On");
    4496             :                 } else {
    4497           0 :                         RETVAL_STRING("Off");
    4498             :                 }
    4499             :         } else {
    4500           0 :                 RETURN_FALSE;
    4501             :         }
    4502             : }
    4503             : /* }}} */
    4504             : 
    4505             : /* {{{ proto bool mb_check_encoding([string var[, string encoding]])
    4506             :    Check if the string is valid for the specified encoding */
    4507         513 : PHP_FUNCTION(mb_check_encoding)
    4508             : {
    4509         513 :         char *var = NULL;
    4510             :         size_t var_len;
    4511         513 :         char *enc = NULL;
    4512             :         size_t enc_len;
    4513             :         mbfl_buffer_converter *convd;
    4514         513 :         const mbfl_encoding *encoding = MBSTRG(current_internal_encoding);
    4515         513 :         mbfl_string string, result, *ret = NULL;
    4516         513 :         long illegalchars = 0;
    4517             : 
    4518         513 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ss", &var, &var_len, &enc, &enc_len) == FAILURE) {
    4519           0 :                 return;
    4520             :         }
    4521             : 
    4522         513 :         if (var == NULL) {
    4523           0 :                 RETURN_BOOL(MBSTRG(illegalchars) == 0);
    4524             :         }
    4525             : 
    4526         513 :         if (enc != NULL) {
    4527         513 :                 encoding = mbfl_name2encoding(enc);
    4528         513 :                 if (!encoding || encoding == &mbfl_encoding_pass) {
    4529           0 :                         php_error_docref(NULL, E_WARNING, "Invalid encoding \"%s\"", enc);
    4530           0 :                         RETURN_FALSE;
    4531             :                 }
    4532             :         }
    4533             : 
    4534         513 :         convd = mbfl_buffer_converter_new2(encoding, encoding, 0);
    4535         513 :         if (convd == NULL) {
    4536           0 :                 php_error_docref(NULL, E_WARNING, "Unable to create converter");
    4537           0 :                 RETURN_FALSE;
    4538             :         }
    4539         513 :         mbfl_buffer_converter_illegal_mode(convd, MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE);
    4540         513 :         mbfl_buffer_converter_illegal_substchar(convd, 0);
    4541             : 
    4542             :         /* initialize string */
    4543         513 :         mbfl_string_init_set(&string, mbfl_no_language_neutral, encoding->no_encoding);
    4544         513 :         mbfl_string_init(&result);
    4545             : 
    4546         513 :         string.val = (unsigned char *)var;
    4547         513 :         string.len = var_len;
    4548         513 :         ret = mbfl_buffer_converter_feed_result(convd, &string, &result);
    4549         513 :         illegalchars = mbfl_buffer_illegalchars(convd);
    4550         513 :         mbfl_buffer_converter_delete(convd);
    4551             : 
    4552         513 :         RETVAL_FALSE;
    4553         513 :         if (ret != NULL) {
    4554         513 :                 if (illegalchars == 0 && string.len == result.len && memcmp(string.val, result.val, string.len) == 0) {
    4555         376 :                         RETVAL_TRUE;
    4556             :                 }
    4557         513 :                 mbfl_string_clear(&result);
    4558             :         }
    4559             : }
    4560             : /* }}} */
    4561             : 
    4562             : /* {{{ php_mb_populate_current_detect_order_list */
    4563       22524 : static void php_mb_populate_current_detect_order_list(void)
    4564             : {
    4565       22524 :         const mbfl_encoding **entry = 0;
    4566             :         size_t nentries;
    4567             : 
    4568       22524 :         if (MBSTRG(current_detect_order_list)) {
    4569           0 :                 return;
    4570             :         }
    4571             : 
    4572       22526 :         if (MBSTRG(detect_order_list) && MBSTRG(detect_order_list_size)) {
    4573           2 :                 nentries = MBSTRG(detect_order_list_size);
    4574           2 :                 entry = (const mbfl_encoding **)safe_emalloc(nentries, sizeof(mbfl_encoding*), 0);
    4575           2 :                 memcpy(entry, MBSTRG(detect_order_list), sizeof(mbfl_encoding*) * nentries);
    4576             :         } else {
    4577       22522 :                 const enum mbfl_no_encoding *src = MBSTRG(default_detect_order_list);
    4578             :                 size_t i;
    4579       22522 :                 nentries = MBSTRG(default_detect_order_list_size);
    4580       22522 :                 entry = (const mbfl_encoding **)safe_emalloc(nentries, sizeof(mbfl_encoding*), 0);
    4581       67608 :                 for (i = 0; i < nentries; i++) {
    4582       45086 :                         entry[i] = mbfl_no2encoding(src[i]);
    4583             :                 }
    4584             :         }
    4585       22524 :         MBSTRG(current_detect_order_list) = entry;
    4586       22524 :         MBSTRG(current_detect_order_list_size) = nentries;
    4587             : }
    4588             : /* }}} */
    4589             : 
    4590             : /* {{{ static int php_mb_encoding_translation() */
    4591         221 : static int php_mb_encoding_translation(void)
    4592             : {
    4593         221 :         return MBSTRG(encoding_translation);
    4594             : }
    4595             : /* }}} */
    4596             : 
    4597             : /* {{{ MBSTRING_API size_t php_mb_mbchar_bytes_ex() */
    4598        1119 : MBSTRING_API size_t php_mb_mbchar_bytes_ex(const char *s, const mbfl_encoding *enc)
    4599             : {
    4600        1119 :         if (enc != NULL) {
    4601        1119 :                 if (enc->flag & MBFL_ENCTYPE_MBCS) {
    4602        1115 :                         if (enc->mblen_table != NULL) {
    4603        1115 :                                 if (s != NULL) return enc->mblen_table[*(unsigned char *)s];
    4604             :                         }
    4605           4 :                 } else if (enc->flag & (MBFL_ENCTYPE_WCS2BE | MBFL_ENCTYPE_WCS2LE)) {
    4606           0 :                         return 2;
    4607           4 :                 } else if (enc->flag & (MBFL_ENCTYPE_WCS4BE | MBFL_ENCTYPE_WCS4LE)) {
    4608           0 :                         return 4;
    4609             :                 }
    4610             :         }
    4611           4 :         return 1;
    4612             : }
    4613             : /* }}} */
    4614             : 
    4615             : /* {{{ MBSTRING_API size_t php_mb_mbchar_bytes() */
    4616           0 : MBSTRING_API size_t php_mb_mbchar_bytes(const char *s)
    4617             : {
    4618           0 :         return php_mb_mbchar_bytes_ex(s, MBSTRG(internal_encoding));
    4619             : }
    4620             : /* }}} */
    4621             : 
    4622             : /* {{{ MBSTRING_API char *php_mb_safe_strrchr_ex() */
    4623           2 : MBSTRING_API char *php_mb_safe_strrchr_ex(const char *s, unsigned int c, size_t nbytes, const mbfl_encoding *enc)
    4624             : {
    4625           2 :         register const char *p = s;
    4626           2 :         char *last=NULL;
    4627             : 
    4628           2 :         if (nbytes == (size_t)-1) {
    4629           0 :                 size_t nb = 0;
    4630             : 
    4631           0 :                 while (*p != '\0') {
    4632           0 :                         if (nb == 0) {
    4633           0 :                                 if ((unsigned char)*p == (unsigned char)c) {
    4634           0 :                                         last = (char *)p;
    4635             :                                 }
    4636           0 :                                 nb = php_mb_mbchar_bytes_ex(p, enc);
    4637           0 :                                 if (nb == 0) {
    4638           0 :                                         return NULL; /* something is going wrong! */
    4639             :                                 }
    4640             :                         }
    4641           0 :                         --nb;
    4642           0 :                         ++p;
    4643             :                 }
    4644             :         } else {
    4645           2 :                 register size_t bcnt = nbytes;
    4646             :                 register size_t nbytes_char;
    4647          22 :                 while (bcnt > 0) {
    4648          18 :                         if ((unsigned char)*p == (unsigned char)c) {
    4649           0 :                                 last = (char *)p;
    4650             :                         }
    4651          18 :                         nbytes_char = php_mb_mbchar_bytes_ex(p, enc);
    4652          18 :                         if (bcnt < nbytes_char) {
    4653           0 :                                 return NULL;
    4654             :                         }
    4655          18 :                         p += nbytes_char;
    4656          18 :                         bcnt -= nbytes_char;
    4657             :                 }
    4658             :         }
    4659           2 :         return last;
    4660             : }
    4661             : /* }}} */
    4662             : 
    4663             : /* {{{ MBSTRING_API char *php_mb_safe_strrchr() */
    4664           0 : MBSTRING_API char *php_mb_safe_strrchr(const char *s, unsigned int c, size_t nbytes)
    4665             : {
    4666           0 :         return php_mb_safe_strrchr_ex(s, c, nbytes, MBSTRG(internal_encoding));
    4667             : }
    4668             : /* }}} */
    4669             : 
    4670             : /* {{{ MBSTRING_API int php_mb_stripos()
    4671             :  */
    4672         606 : MBSTRING_API int php_mb_stripos(int mode, const char *old_haystack, unsigned int old_haystack_len, const char *old_needle, unsigned int old_needle_len, long offset, const char *from_encoding)
    4673             : {
    4674             :         int n;
    4675             :         mbfl_string haystack, needle;
    4676         606 :         n = -1;
    4677             : 
    4678         606 :         mbfl_string_init(&haystack);
    4679         606 :         mbfl_string_init(&needle);
    4680         606 :         haystack.no_language = MBSTRG(language);
    4681         606 :         haystack.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    4682         606 :         needle.no_language = MBSTRG(language);
    4683         606 :         needle.no_encoding = MBSTRG(current_internal_encoding)->no_encoding;
    4684             : 
    4685             :         do {
    4686         606 :                 size_t len = 0;
    4687         606 :                 haystack.val = (unsigned char *)php_unicode_convert_case(PHP_UNICODE_CASE_UPPER, (char *)old_haystack, old_haystack_len, &len, from_encoding);
    4688         606 :                 haystack.len = len;
    4689             : 
    4690         606 :                 if (!haystack.val) {
    4691          40 :                         break;
    4692             :                 }
    4693             : 
    4694         566 :                 if (haystack.len <= 0) {
    4695          32 :                         break;
    4696             :                 }
    4697             : 
    4698         534 :                 needle.val = (unsigned char *)php_unicode_convert_case(PHP_UNICODE_CASE_UPPER, (char *)old_needle, old_needle_len, &len, from_encoding);
    4699         534 :                 needle.len = len;
    4700             : 
    4701         534 :                 if (!needle.val) {
    4702           0 :                         break;
    4703             :                 }
    4704             : 
    4705         534 :                 if (needle.len <= 0) {
    4706          16 :                         break;
    4707             :                 }
    4708             : 
    4709         518 :                 haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(from_encoding);
    4710         518 :                 if (haystack.no_encoding == mbfl_no_encoding_invalid) {
    4711           0 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", from_encoding);
    4712           0 :                         break;
    4713             :                 }
    4714             : 
    4715             :                 {
    4716         518 :                         int haystack_char_len = mbfl_strlen(&haystack);
    4717             : 
    4718         518 :                         if (mode) {
    4719         250 :                                 if ((offset > 0 && offset > haystack_char_len) ||
    4720           7 :                                         (offset < 0 && -offset > haystack_char_len)) {
    4721          14 :                                         php_error_docref(NULL, E_WARNING, "Offset is greater than the length of haystack string");
    4722          14 :                                         break;
    4723             :                                 }
    4724             :                         } else {
    4725         275 :                                 if (offset < 0 || offset > haystack_char_len) {
    4726          26 :                                         php_error_docref(NULL, E_WARNING, "Offset not contained in string");
    4727          26 :                                         break;
    4728             :                                 }
    4729             :                         }
    4730             :                 }
    4731             : 
    4732         478 :                 n = mbfl_strpos(&haystack, &needle, offset, mode);
    4733             :         } while(0);
    4734             : 
    4735         606 :         if (haystack.val) {
    4736         566 :                 efree(haystack.val);
    4737             :         }
    4738             : 
    4739         606 :         if (needle.val) {
    4740         534 :                 efree(needle.val);
    4741             :         }
    4742             : 
    4743         606 :         return n;
    4744             : }
    4745             : /* }}} */
    4746             : 
    4747           1 : static void php_mb_gpc_get_detect_order(const zend_encoding ***list, size_t *list_size) /* {{{ */
    4748             : {
    4749           1 :         *list = (const zend_encoding **)MBSTRG(http_input_list);
    4750           1 :         *list_size = MBSTRG(http_input_list_size);
    4751           1 : }
    4752             : /* }}} */
    4753             : 
    4754           0 : static void php_mb_gpc_set_input_encoding(const zend_encoding *encoding) /* {{{ */
    4755             : {
    4756           0 :         MBSTRG(http_input_identify) = (const mbfl_encoding*)encoding;
    4757           0 : }
    4758             : /* }}} */
    4759             : 
    4760             : #endif  /* HAVE_MBSTRING */
    4761             : 
    4762             : /*
    4763             :  * Local variables:
    4764             :  * tab-width: 4
    4765             :  * c-basic-offset: 4
    4766             :  * End:
    4767             :  * vim600: fdm=marker
    4768             :  * vim: noet sw=4 ts=4
    4769             :  */

Generated by: LCOV version 1.10

Generated at Tue, 09 Feb 2016 10:48:44 +0000 (26 hours ago)

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