diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2013-03-14 05:42:27 +0000 |
---|---|---|
committer | <> | 2013-04-03 16:25:08 +0000 |
commit | c4dd7a1a684490673e25aaf4fabec5df138854c4 (patch) | |
tree | 4d57c44caae4480efff02b90b9be86f44bf25409 /ext/mbstring/mbstring.c | |
download | php2-master.tar.gz |
Imported from /home/lorry/working-area/delta_php2/php-5.4.13.tar.bz2.HEADphp-5.4.13master
Diffstat (limited to 'ext/mbstring/mbstring.c')
-rw-r--r-- | ext/mbstring/mbstring.c | 4754 |
1 files changed, 4754 insertions, 0 deletions
diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c new file mode 100644 index 0000000..a42f2e8 --- /dev/null +++ b/ext/mbstring/mbstring.c @@ -0,0 +1,4754 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Tsukada Takuya <tsukada@fminn.nagano.nagano.jp> | + | Rui Hirokawa <hirokawa@php.net> | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +/* + * PHP 4 Multibyte String module "mbstring" + * + * History: + * 2000.5.19 Release php-4.0RC2_jstring-1.0 + * 2001.4.1 Release php4_jstring-1.0.91 + * 2001.4.30 Release php4_jstring-1.1 (contribute to The PHP Group) + * 2001.5.1 Renamed from jstring to mbstring (hirokawa@php.net) + */ + +/* + * PHP3 Internationalization support program. + * + * Copyright (c) 1999,2000 by the PHP3 internationalization team. + * All rights reserved. + * + * See README_PHP3-i18n-ja for more detail. + * + * Authors: + * Hironori Sato <satoh@jpnnet.com> + * Shigeru Kanemoto <sgk@happysize.co.jp> + * Tsukada Takuya <tsukada@fminn.nagano.nagano.jp> + * Rui Hirokawa <rui_hirokawa@ybb.ne.jp> + */ + +/* {{{ includes */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "php_variables.h" +#include "mbstring.h" +#include "ext/standard/php_string.h" +#include "ext/standard/php_mail.h" +#include "ext/standard/exec.h" +#include "ext/standard/php_smart_str.h" +#include "ext/standard/url.h" +#include "main/php_output.h" +#include "ext/standard/info.h" + +#include "libmbfl/mbfl/mbfl_allocators.h" +#include "libmbfl/mbfl/mbfilter_pass.h" + +#include "php_variables.h" +#include "php_globals.h" +#include "rfc1867.h" +#include "php_content_types.h" +#include "SAPI.h" +#include "php_unicode.h" +#include "TSRM.h" + +#include "mb_gpc.h" + +#if HAVE_MBREGEX +#include "php_mbregex.h" +#endif + +#include "zend_multibyte.h" + +#if HAVE_ONIG +#include "php_onig_compat.h" +#include <oniguruma.h> +#undef UChar +#elif HAVE_PCRE || HAVE_BUNDLED_PCRE +#include "ext/pcre/php_pcre.h" +#endif +/* }}} */ + +#if HAVE_MBSTRING + +/* {{{ prototypes */ +ZEND_DECLARE_MODULE_GLOBALS(mbstring) + +static PHP_GINIT_FUNCTION(mbstring); +static PHP_GSHUTDOWN_FUNCTION(mbstring); + +static void php_mb_populate_current_detect_order_list(TSRMLS_D); + +static int php_mb_encoding_translation(TSRMLS_D); + +static void php_mb_gpc_get_detect_order(const zend_encoding ***list, size_t *list_size TSRMLS_DC); + +static void php_mb_gpc_set_input_encoding(const zend_encoding *encoding TSRMLS_DC); + +/* }}} */ + +/* {{{ php_mb_default_identify_list */ +typedef struct _php_mb_nls_ident_list { + enum mbfl_no_language lang; + const enum mbfl_no_encoding *list; + size_t list_size; +} php_mb_nls_ident_list; + +static const enum mbfl_no_encoding php_mb_default_identify_list_ja[] = { + mbfl_no_encoding_ascii, + mbfl_no_encoding_jis, + mbfl_no_encoding_utf8, + mbfl_no_encoding_euc_jp, + mbfl_no_encoding_sjis +}; + +static const enum mbfl_no_encoding php_mb_default_identify_list_cn[] = { + mbfl_no_encoding_ascii, + mbfl_no_encoding_utf8, + mbfl_no_encoding_euc_cn, + mbfl_no_encoding_cp936 +}; + +static const enum mbfl_no_encoding php_mb_default_identify_list_tw_hk[] = { + mbfl_no_encoding_ascii, + mbfl_no_encoding_utf8, + mbfl_no_encoding_euc_tw, + mbfl_no_encoding_big5 +}; + +static const enum mbfl_no_encoding php_mb_default_identify_list_kr[] = { + mbfl_no_encoding_ascii, + mbfl_no_encoding_utf8, + mbfl_no_encoding_euc_kr, + mbfl_no_encoding_uhc +}; + +static const enum mbfl_no_encoding php_mb_default_identify_list_ru[] = { + mbfl_no_encoding_ascii, + mbfl_no_encoding_utf8, + mbfl_no_encoding_koi8r, + mbfl_no_encoding_cp1251, + mbfl_no_encoding_cp866 +}; + +static const enum mbfl_no_encoding php_mb_default_identify_list_hy[] = { + mbfl_no_encoding_ascii, + mbfl_no_encoding_utf8, + mbfl_no_encoding_armscii8 +}; + +static const enum mbfl_no_encoding php_mb_default_identify_list_tr[] = { + mbfl_no_encoding_ascii, + mbfl_no_encoding_utf8, + mbfl_no_encoding_cp1254, + mbfl_no_encoding_8859_9 +}; + +static const enum mbfl_no_encoding php_mb_default_identify_list_ua[] = { + mbfl_no_encoding_ascii, + mbfl_no_encoding_utf8, + mbfl_no_encoding_koi8u +}; + +static const enum mbfl_no_encoding php_mb_default_identify_list_neut[] = { + mbfl_no_encoding_ascii, + mbfl_no_encoding_utf8 +}; + + +static const php_mb_nls_ident_list php_mb_default_identify_list[] = { + { 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]) }, + { 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]) }, + { 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]) }, + { 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]) }, + { 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]) }, + { 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]) }, + { 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]) }, + { 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]) }, + { 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]) } +}; + +/* }}} */ + +/* {{{ mb_overload_def mb_ovld[] */ +static const struct mb_overload_def mb_ovld[] = { + {MB_OVERLOAD_MAIL, "mail", "mb_send_mail", "mb_orig_mail"}, + {MB_OVERLOAD_STRING, "strlen", "mb_strlen", "mb_orig_strlen"}, + {MB_OVERLOAD_STRING, "strpos", "mb_strpos", "mb_orig_strpos"}, + {MB_OVERLOAD_STRING, "strrpos", "mb_strrpos", "mb_orig_strrpos"}, + {MB_OVERLOAD_STRING, "stripos", "mb_stripos", "mb_orig_stripos"}, + {MB_OVERLOAD_STRING, "strripos", "mb_strripos", "mb_orig_strripos"}, + {MB_OVERLOAD_STRING, "strstr", "mb_strstr", "mb_orig_strstr"}, + {MB_OVERLOAD_STRING, "strrchr", "mb_strrchr", "mb_orig_strrchr"}, + {MB_OVERLOAD_STRING, "stristr", "mb_stristr", "mb_orig_stristr"}, + {MB_OVERLOAD_STRING, "substr", "mb_substr", "mb_orig_substr"}, + {MB_OVERLOAD_STRING, "strtolower", "mb_strtolower", "mb_orig_strtolower"}, + {MB_OVERLOAD_STRING, "strtoupper", "mb_strtoupper", "mb_orig_strtoupper"}, + {MB_OVERLOAD_STRING, "substr_count", "mb_substr_count", "mb_orig_substr_count"}, +#if HAVE_MBREGEX + {MB_OVERLOAD_REGEX, "ereg", "mb_ereg", "mb_orig_ereg"}, + {MB_OVERLOAD_REGEX, "eregi", "mb_eregi", "mb_orig_eregi"}, + {MB_OVERLOAD_REGEX, "ereg_replace", "mb_ereg_replace", "mb_orig_ereg_replace"}, + {MB_OVERLOAD_REGEX, "eregi_replace", "mb_eregi_replace", "mb_orig_eregi_replace"}, + {MB_OVERLOAD_REGEX, "split", "mb_split", "mb_orig_split"}, +#endif + {0, NULL, NULL, NULL} +}; +/* }}} */ + +/* {{{ arginfo */ +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_language, 0, 0, 0) + ZEND_ARG_INFO(0, language) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_internal_encoding, 0, 0, 0) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_http_input, 0, 0, 0) + ZEND_ARG_INFO(0, type) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_http_output, 0, 0, 0) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_detect_order, 0, 0, 0) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_substitute_character, 0, 0, 0) + ZEND_ARG_INFO(0, substchar) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_preferred_mime_name, 0, 0, 1) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_parse_str, 0, 0, 1) + ZEND_ARG_INFO(0, encoded_string) + ZEND_ARG_INFO(1, result) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_output_handler, 0, 0, 2) + ZEND_ARG_INFO(0, contents) + ZEND_ARG_INFO(0, status) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strlen, 0, 0, 1) + ZEND_ARG_INFO(0, str) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strpos, 0, 0, 2) + ZEND_ARG_INFO(0, haystack) + ZEND_ARG_INFO(0, needle) + ZEND_ARG_INFO(0, offset) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strrpos, 0, 0, 2) + ZEND_ARG_INFO(0, haystack) + ZEND_ARG_INFO(0, needle) + ZEND_ARG_INFO(0, offset) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_stripos, 0, 0, 2) + ZEND_ARG_INFO(0, haystack) + ZEND_ARG_INFO(0, needle) + ZEND_ARG_INFO(0, offset) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strripos, 0, 0, 2) + ZEND_ARG_INFO(0, haystack) + ZEND_ARG_INFO(0, needle) + ZEND_ARG_INFO(0, offset) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strstr, 0, 0, 2) + ZEND_ARG_INFO(0, haystack) + ZEND_ARG_INFO(0, needle) + ZEND_ARG_INFO(0, part) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strrchr, 0, 0, 2) + ZEND_ARG_INFO(0, haystack) + ZEND_ARG_INFO(0, needle) + ZEND_ARG_INFO(0, part) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_stristr, 0, 0, 2) + ZEND_ARG_INFO(0, haystack) + ZEND_ARG_INFO(0, needle) + ZEND_ARG_INFO(0, part) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strrichr, 0, 0, 2) + ZEND_ARG_INFO(0, haystack) + ZEND_ARG_INFO(0, needle) + ZEND_ARG_INFO(0, part) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_substr_count, 0, 0, 2) + ZEND_ARG_INFO(0, haystack) + ZEND_ARG_INFO(0, needle) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_substr, 0, 0, 2) + ZEND_ARG_INFO(0, str) + ZEND_ARG_INFO(0, start) + ZEND_ARG_INFO(0, length) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strcut, 0, 0, 2) + ZEND_ARG_INFO(0, str) + ZEND_ARG_INFO(0, start) + ZEND_ARG_INFO(0, length) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strwidth, 0, 0, 1) + ZEND_ARG_INFO(0, str) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strimwidth, 0, 0, 3) + ZEND_ARG_INFO(0, str) + ZEND_ARG_INFO(0, start) + ZEND_ARG_INFO(0, width) + ZEND_ARG_INFO(0, trimmarker) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_convert_encoding, 0, 0, 2) + ZEND_ARG_INFO(0, str) + ZEND_ARG_INFO(0, to) + ZEND_ARG_INFO(0, from) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_convert_case, 0, 0, 2) + ZEND_ARG_INFO(0, sourcestring) + ZEND_ARG_INFO(0, mode) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strtoupper, 0, 0, 1) + ZEND_ARG_INFO(0, sourcestring) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strtolower, 0, 0, 1) + ZEND_ARG_INFO(0, sourcestring) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_detect_encoding, 0, 0, 1) + ZEND_ARG_INFO(0, str) + ZEND_ARG_INFO(0, encoding_list) + ZEND_ARG_INFO(0, strict) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_mb_list_encodings, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_encoding_aliases, 0, 0, 1) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_encode_mimeheader, 0, 0, 1) + ZEND_ARG_INFO(0, str) + ZEND_ARG_INFO(0, charset) + ZEND_ARG_INFO(0, transfer) + ZEND_ARG_INFO(0, linefeed) + ZEND_ARG_INFO(0, indent) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_decode_mimeheader, 0, 0, 1) + ZEND_ARG_INFO(0, string) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_convert_kana, 0, 0, 1) + ZEND_ARG_INFO(0, str) + ZEND_ARG_INFO(0, option) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_convert_variables, 1, 0, 3) + ZEND_ARG_INFO(0, to) + ZEND_ARG_INFO(0, from) + ZEND_ARG_INFO(1, ...) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_encode_numericentity, 0, 0, 2) + ZEND_ARG_INFO(0, string) + ZEND_ARG_INFO(0, convmap) + ZEND_ARG_INFO(0, encoding) + ZEND_ARG_INFO(0, is_hex) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_decode_numericentity, 0, 0, 2) + ZEND_ARG_INFO(0, string) + ZEND_ARG_INFO(0, convmap) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_send_mail, 0, 0, 3) + ZEND_ARG_INFO(0, to) + ZEND_ARG_INFO(0, subject) + ZEND_ARG_INFO(0, message) + ZEND_ARG_INFO(0, additional_headers) + ZEND_ARG_INFO(0, additional_parameters) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_get_info, 0, 0, 0) + ZEND_ARG_INFO(0, type) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_check_encoding, 0, 0, 0) + ZEND_ARG_INFO(0, var) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_regex_encoding, 0, 0, 0) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg, 0, 0, 2) + ZEND_ARG_INFO(0, pattern) + ZEND_ARG_INFO(0, string) + ZEND_ARG_INFO(1, registers) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_eregi, 0, 0, 2) + ZEND_ARG_INFO(0, pattern) + ZEND_ARG_INFO(0, string) + ZEND_ARG_INFO(1, registers) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_replace, 0, 0, 3) + ZEND_ARG_INFO(0, pattern) + ZEND_ARG_INFO(0, replacement) + ZEND_ARG_INFO(0, string) + ZEND_ARG_INFO(0, option) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_eregi_replace, 0, 0, 3) + ZEND_ARG_INFO(0, pattern) + ZEND_ARG_INFO(0, replacement) + ZEND_ARG_INFO(0, string) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_replace_callback, 0, 0, 3) + ZEND_ARG_INFO(0, pattern) + ZEND_ARG_INFO(0, callback) + ZEND_ARG_INFO(0, string) + ZEND_ARG_INFO(0, option) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_split, 0, 0, 2) + ZEND_ARG_INFO(0, pattern) + ZEND_ARG_INFO(0, string) + ZEND_ARG_INFO(0, limit) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_match, 0, 0, 2) + ZEND_ARG_INFO(0, pattern) + ZEND_ARG_INFO(0, string) + ZEND_ARG_INFO(0, option) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_search, 0, 0, 0) + ZEND_ARG_INFO(0, pattern) + ZEND_ARG_INFO(0, option) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_search_pos, 0, 0, 0) + ZEND_ARG_INFO(0, pattern) + ZEND_ARG_INFO(0, option) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_search_regs, 0, 0, 0) + ZEND_ARG_INFO(0, pattern) + ZEND_ARG_INFO(0, option) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_search_init, 0, 0, 1) + ZEND_ARG_INFO(0, string) + ZEND_ARG_INFO(0, pattern) + ZEND_ARG_INFO(0, option) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_mb_ereg_search_getregs, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_mb_ereg_search_getpos, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_search_setpos, 0, 0, 1) + ZEND_ARG_INFO(0, position) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_regex_set_options, 0, 0, 0) + ZEND_ARG_INFO(0, options) +ZEND_END_ARG_INFO() +/* }}} */ + +/* {{{ zend_function_entry mbstring_functions[] */ +const zend_function_entry mbstring_functions[] = { + PHP_FE(mb_convert_case, arginfo_mb_convert_case) + PHP_FE(mb_strtoupper, arginfo_mb_strtoupper) + PHP_FE(mb_strtolower, arginfo_mb_strtolower) + PHP_FE(mb_language, arginfo_mb_language) + PHP_FE(mb_internal_encoding, arginfo_mb_internal_encoding) + PHP_FE(mb_http_input, arginfo_mb_http_input) + PHP_FE(mb_http_output, arginfo_mb_http_output) + PHP_FE(mb_detect_order, arginfo_mb_detect_order) + PHP_FE(mb_substitute_character, arginfo_mb_substitute_character) + PHP_FE(mb_parse_str, arginfo_mb_parse_str) + PHP_FE(mb_output_handler, arginfo_mb_output_handler) + PHP_FE(mb_preferred_mime_name, arginfo_mb_preferred_mime_name) + PHP_FE(mb_strlen, arginfo_mb_strlen) + PHP_FE(mb_strpos, arginfo_mb_strpos) + PHP_FE(mb_strrpos, arginfo_mb_strrpos) + PHP_FE(mb_stripos, arginfo_mb_stripos) + PHP_FE(mb_strripos, arginfo_mb_strripos) + PHP_FE(mb_strstr, arginfo_mb_strstr) + PHP_FE(mb_strrchr, arginfo_mb_strrchr) + PHP_FE(mb_stristr, arginfo_mb_stristr) + PHP_FE(mb_strrichr, arginfo_mb_strrichr) + PHP_FE(mb_substr_count, arginfo_mb_substr_count) + PHP_FE(mb_substr, arginfo_mb_substr) + PHP_FE(mb_strcut, arginfo_mb_strcut) + PHP_FE(mb_strwidth, arginfo_mb_strwidth) + PHP_FE(mb_strimwidth, arginfo_mb_strimwidth) + PHP_FE(mb_convert_encoding, arginfo_mb_convert_encoding) + PHP_FE(mb_detect_encoding, arginfo_mb_detect_encoding) + PHP_FE(mb_list_encodings, arginfo_mb_list_encodings) + PHP_FE(mb_encoding_aliases, arginfo_mb_encoding_aliases) + PHP_FE(mb_convert_kana, arginfo_mb_convert_kana) + PHP_FE(mb_encode_mimeheader, arginfo_mb_encode_mimeheader) + PHP_FE(mb_decode_mimeheader, arginfo_mb_decode_mimeheader) + PHP_FE(mb_convert_variables, arginfo_mb_convert_variables) + PHP_FE(mb_encode_numericentity, arginfo_mb_encode_numericentity) + PHP_FE(mb_decode_numericentity, arginfo_mb_decode_numericentity) + PHP_FE(mb_send_mail, arginfo_mb_send_mail) + PHP_FE(mb_get_info, arginfo_mb_get_info) + PHP_FE(mb_check_encoding, arginfo_mb_check_encoding) +#if HAVE_MBREGEX + PHP_MBREGEX_FUNCTION_ENTRIES +#endif + PHP_FE_END +}; +/* }}} */ + +/* {{{ zend_module_entry mbstring_module_entry */ +zend_module_entry mbstring_module_entry = { + STANDARD_MODULE_HEADER, + "mbstring", + mbstring_functions, + PHP_MINIT(mbstring), + PHP_MSHUTDOWN(mbstring), + PHP_RINIT(mbstring), + PHP_RSHUTDOWN(mbstring), + PHP_MINFO(mbstring), + NO_VERSION_YET, + PHP_MODULE_GLOBALS(mbstring), + PHP_GINIT(mbstring), + PHP_GSHUTDOWN(mbstring), + NULL, + STANDARD_MODULE_PROPERTIES_EX +}; +/* }}} */ + +/* {{{ static sapi_post_entry php_post_entries[] */ +static sapi_post_entry php_post_entries[] = { + { DEFAULT_POST_CONTENT_TYPE, sizeof(DEFAULT_POST_CONTENT_TYPE)-1, sapi_read_standard_form_data, php_std_post_handler }, + { MULTIPART_CONTENT_TYPE, sizeof(MULTIPART_CONTENT_TYPE)-1, NULL, rfc1867_post_handler }, + { NULL, 0, NULL, NULL } +}; +/* }}} */ + +#ifdef COMPILE_DL_MBSTRING +ZEND_GET_MODULE(mbstring) +#endif + +/* {{{ allocators */ +static void *_php_mb_allocators_malloc(unsigned int sz) +{ + return emalloc(sz); +} + +static void *_php_mb_allocators_realloc(void *ptr, unsigned int sz) +{ + return erealloc(ptr, sz); +} + +static void *_php_mb_allocators_calloc(unsigned int nelems, unsigned int szelem) +{ + return ecalloc(nelems, szelem); +} + +static void _php_mb_allocators_free(void *ptr) +{ + efree(ptr); +} + +static void *_php_mb_allocators_pmalloc(unsigned int sz) +{ + return pemalloc(sz, 1); +} + +static void *_php_mb_allocators_prealloc(void *ptr, unsigned int sz) +{ + return perealloc(ptr, sz, 1); +} + +static void _php_mb_allocators_pfree(void *ptr) +{ + pefree(ptr, 1); +} + +static mbfl_allocators _php_mb_allocators = { + _php_mb_allocators_malloc, + _php_mb_allocators_realloc, + _php_mb_allocators_calloc, + _php_mb_allocators_free, + _php_mb_allocators_pmalloc, + _php_mb_allocators_prealloc, + _php_mb_allocators_pfree +}; +/* }}} */ + +/* {{{ static sapi_post_entry mbstr_post_entries[] */ +static sapi_post_entry mbstr_post_entries[] = { + { DEFAULT_POST_CONTENT_TYPE, sizeof(DEFAULT_POST_CONTENT_TYPE)-1, sapi_read_standard_form_data, php_mb_post_handler }, + { MULTIPART_CONTENT_TYPE, sizeof(MULTIPART_CONTENT_TYPE)-1, NULL, rfc1867_post_handler }, + { NULL, 0, NULL, NULL } +}; +/* }}} */ + +/* {{{ static int php_mb_parse_encoding_list() + * Return 0 if input contains any illegal encoding, otherwise 1. + * Even if any illegal encoding is detected the result may contain a list + * of parsed encodings. + */ +static int +php_mb_parse_encoding_list(const char *value, size_t value_length, const mbfl_encoding ***return_list, size_t *return_size, int persistent TSRMLS_DC) +{ + int size, bauto, ret = SUCCESS; + size_t n; + char *p, *p1, *p2, *endp, *tmpstr; + const mbfl_encoding **entry, **list; + + list = NULL; + if (value == NULL || value_length <= 0) { + if (return_list) { + *return_list = NULL; + } + if (return_size) { + *return_size = 0; + } + return FAILURE; + } else { + /* copy the value string for work */ + if (value[0]=='"' && value[value_length-1]=='"' && value_length>2) { + tmpstr = (char *)estrndup(value+1, value_length-2); + value_length -= 2; + } + else + tmpstr = (char *)estrndup(value, value_length); + if (tmpstr == NULL) { + return FAILURE; + } + /* count the number of listed encoding names */ + endp = tmpstr + value_length; + n = 1; + p1 = tmpstr; + while ((p2 = php_memnstr(p1, ",", 1, endp)) != NULL) { + p1 = p2 + 1; + n++; + } + size = n + MBSTRG(default_detect_order_list_size); + /* make list */ + list = (const mbfl_encoding **)pecalloc(size, sizeof(mbfl_encoding*), persistent); + if (list != NULL) { + entry = list; + n = 0; + bauto = 0; + p1 = tmpstr; + do { + p2 = p = php_memnstr(p1, ",", 1, endp); + if (p == NULL) { + p = endp; + } + *p = '\0'; + /* trim spaces */ + while (p1 < p && (*p1 == ' ' || *p1 == '\t')) { + p1++; + } + p--; + while (p > p1 && (*p == ' ' || *p == '\t')) { + *p = '\0'; + p--; + } + /* convert to the encoding number and check encoding */ + if (strcasecmp(p1, "auto") == 0) { + if (!bauto) { + const enum mbfl_no_encoding *src = MBSTRG(default_detect_order_list); + const size_t identify_list_size = MBSTRG(default_detect_order_list_size); + size_t i; + bauto = 1; + for (i = 0; i < identify_list_size; i++) { + *entry++ = mbfl_no2encoding(*src++); + n++; + } + } + } else { + const mbfl_encoding *encoding = mbfl_name2encoding(p1); + if (encoding) { + *entry++ = encoding; + n++; + } else { + ret = 0; + } + } + p1 = p2 + 1; + } while (n < size && p2 != NULL); + if (n > 0) { + if (return_list) { + *return_list = list; + } else { + pefree(list, persistent); + } + } else { + pefree(list, persistent); + if (return_list) { + *return_list = NULL; + } + ret = 0; + } + if (return_size) { + *return_size = n; + } + } else { + if (return_list) { + *return_list = NULL; + } + if (return_size) { + *return_size = 0; + } + ret = 0; + } + efree(tmpstr); + } + + return ret; +} +/* }}} */ + +/* {{{ static int php_mb_parse_encoding_array() + * Return 0 if input contains any illegal encoding, otherwise 1. + * Even if any illegal encoding is detected the result may contain a list + * of parsed encodings. + */ +static int +php_mb_parse_encoding_array(zval *array, const mbfl_encoding ***return_list, size_t *return_size, int persistent TSRMLS_DC) +{ + zval **hash_entry; + HashTable *target_hash; + int i, n, size, bauto, ret = SUCCESS; + const mbfl_encoding **list, **entry; + + list = NULL; + if (Z_TYPE_P(array) == IS_ARRAY) { + target_hash = Z_ARRVAL_P(array); + zend_hash_internal_pointer_reset(target_hash); + i = zend_hash_num_elements(target_hash); + size = i + MBSTRG(default_detect_order_list_size); + list = (const mbfl_encoding **)pecalloc(size, sizeof(mbfl_encoding*), persistent); + if (list != NULL) { + entry = list; + bauto = 0; + n = 0; + while (i > 0) { + if (zend_hash_get_current_data(target_hash, (void **) &hash_entry) == FAILURE) { + break; + } + convert_to_string_ex(hash_entry); + if (strcasecmp(Z_STRVAL_PP(hash_entry), "auto") == 0) { + if (!bauto) { + const enum mbfl_no_encoding *src = MBSTRG(default_detect_order_list); + const size_t identify_list_size = MBSTRG(default_detect_order_list_size); + size_t j; + + bauto = 1; + for (j = 0; j < identify_list_size; j++) { + *entry++ = mbfl_no2encoding(*src++); + n++; + } + } + } else { + const mbfl_encoding *encoding = mbfl_name2encoding(Z_STRVAL_PP(hash_entry)); + if (encoding) { + *entry++ = encoding; + n++; + } else { + ret = FAILURE; + } + } + zend_hash_move_forward(target_hash); + i--; + } + if (n > 0) { + if (return_list) { + *return_list = list; + } else { + pefree(list, persistent); + } + } else { + pefree(list, persistent); + if (return_list) { + *return_list = NULL; + } + ret = FAILURE; + } + if (return_size) { + *return_size = n; + } + } else { + if (return_list) { + *return_list = NULL; + } + if (return_size) { + *return_size = 0; + } + ret = FAILURE; + } + } + + return ret; +} +/* }}} */ + +/* {{{ zend_multibyte interface */ +static const zend_encoding* php_mb_zend_encoding_fetcher(const char *encoding_name TSRMLS_DC) +{ + return (const zend_encoding*)mbfl_name2encoding(encoding_name); +} + +static const char *php_mb_zend_encoding_name_getter(const zend_encoding *encoding) +{ + return ((const mbfl_encoding *)encoding)->name; +} + +static int php_mb_zend_encoding_lexer_compatibility_checker(const zend_encoding *_encoding) +{ + const mbfl_encoding *encoding = (const mbfl_encoding*)_encoding; + if (encoding->flag & MBFL_ENCTYPE_SBCS) { + return 1; + } + if ((encoding->flag & (MBFL_ENCTYPE_MBCS | MBFL_ENCTYPE_GL_UNSAFE)) == MBFL_ENCTYPE_MBCS) { + return 1; + } + return 0; +} + +static const zend_encoding *php_mb_zend_encoding_detector(const unsigned char *arg_string, size_t arg_length, const zend_encoding **list, size_t list_size TSRMLS_DC) +{ + mbfl_string string; + + if (!list) { + list = (const zend_encoding **)MBSTRG(current_detect_order_list); + list_size = MBSTRG(current_detect_order_list_size); + } + + mbfl_string_init(&string); + string.no_language = MBSTRG(language); + string.val = (unsigned char *)arg_string; + string.len = arg_length; + return (const zend_encoding *) mbfl_identify_encoding2(&string, (const mbfl_encoding **)list, list_size, 0); +} + +static size_t php_mb_zend_encoding_converter(unsigned char **to, size_t *to_length, const unsigned char *from, size_t from_length, const zend_encoding *encoding_to, const zend_encoding *encoding_from TSRMLS_DC) +{ + mbfl_string string, result; + mbfl_buffer_converter *convd; + int status, loc; + + /* new encoding */ + /* initialize string */ + mbfl_string_init(&string); + mbfl_string_init(&result); + string.no_encoding = ((const mbfl_encoding*)encoding_from)->no_encoding; + string.no_language = MBSTRG(language); + string.val = (unsigned char*)from; + string.len = from_length; + + /* initialize converter */ + convd = mbfl_buffer_converter_new2((const mbfl_encoding *)encoding_from, (const mbfl_encoding *)encoding_to, string.len); + if (convd == NULL) { + return -1; + } + mbfl_buffer_converter_illegal_mode(convd, MBSTRG(current_filter_illegal_mode)); + mbfl_buffer_converter_illegal_substchar(convd, MBSTRG(current_filter_illegal_substchar)); + + /* do it */ + status = mbfl_buffer_converter_feed2(convd, &string, &loc); + if (status) { + mbfl_buffer_converter_delete(convd); + return (size_t)-1; + } + + mbfl_buffer_converter_flush(convd); + if (!mbfl_buffer_converter_result(convd, &result)) { + mbfl_buffer_converter_delete(convd); + return (size_t)-1; + } + + *to = result.val; + *to_length = result.len; + + mbfl_buffer_converter_delete(convd); + + return loc; +} + +static int php_mb_zend_encoding_list_parser(const char *encoding_list, size_t encoding_list_len, const zend_encoding ***return_list, size_t *return_size, int persistent TSRMLS_DC) +{ + return php_mb_parse_encoding_list(encoding_list, encoding_list_len, (const mbfl_encoding ***)return_list, return_size, persistent TSRMLS_CC); +} + +static const zend_encoding *php_mb_zend_internal_encoding_getter(TSRMLS_D) +{ + return (const zend_encoding *)MBSTRG(internal_encoding); +} + +static int php_mb_zend_internal_encoding_setter(const zend_encoding *encoding TSRMLS_DC) +{ + MBSTRG(internal_encoding) = (const mbfl_encoding *)encoding; + return SUCCESS; +} + +static zend_multibyte_functions php_mb_zend_multibyte_functions = { + "mbstring", + php_mb_zend_encoding_fetcher, + php_mb_zend_encoding_name_getter, + php_mb_zend_encoding_lexer_compatibility_checker, + php_mb_zend_encoding_detector, + php_mb_zend_encoding_converter, + php_mb_zend_encoding_list_parser, + php_mb_zend_internal_encoding_getter, + php_mb_zend_internal_encoding_setter +}; +/* }}} */ + +static void *_php_mb_compile_regex(const char *pattern TSRMLS_DC); +static int _php_mb_match_regex(void *opaque, const char *str, size_t str_len); +static void _php_mb_free_regex(void *opaque); + +#if HAVE_ONIG +/* {{{ _php_mb_compile_regex */ +static void *_php_mb_compile_regex(const char *pattern TSRMLS_DC) +{ + php_mb_regex_t *retval; + OnigErrorInfo err_info; + int err_code; + + if ((err_code = onig_new(&retval, + (const OnigUChar *)pattern, + (const OnigUChar *)pattern + strlen(pattern), + ONIG_OPTION_IGNORECASE | ONIG_OPTION_DONT_CAPTURE_GROUP, + ONIG_ENCODING_ASCII, &OnigSyntaxPerl, &err_info))) { + OnigUChar err_str[ONIG_MAX_ERROR_MESSAGE_LEN]; + onig_error_code_to_str(err_str, err_code, err_info); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s: %s", pattern, err_str); + retval = NULL; + } + return retval; +} +/* }}} */ + +/* {{{ _php_mb_match_regex */ +static int _php_mb_match_regex(void *opaque, const char *str, size_t str_len) +{ + return onig_search((php_mb_regex_t *)opaque, (const OnigUChar *)str, + (const OnigUChar*)str + str_len, (const OnigUChar *)str, + (const OnigUChar*)str + str_len, NULL, ONIG_OPTION_NONE) >= 0; +} +/* }}} */ + +/* {{{ _php_mb_free_regex */ +static void _php_mb_free_regex(void *opaque) +{ + onig_free((php_mb_regex_t *)opaque); +} +/* }}} */ +#elif HAVE_PCRE || HAVE_BUNDLED_PCRE +/* {{{ _php_mb_compile_regex */ +static void *_php_mb_compile_regex(const char *pattern TSRMLS_DC) +{ + pcre *retval; + const char *err_str; + int err_offset; + + if (!(retval = pcre_compile(pattern, + PCRE_CASELESS, &err_str, &err_offset, NULL))) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s (offset=%d): %s", pattern, err_offset, err_str); + } + return retval; +} +/* }}} */ + +/* {{{ _php_mb_match_regex */ +static int _php_mb_match_regex(void *opaque, const char *str, size_t str_len) +{ + return pcre_exec((pcre *)opaque, NULL, str, (int)str_len, 0, + 0, NULL, 0) >= 0; +} +/* }}} */ + +/* {{{ _php_mb_free_regex */ +static void _php_mb_free_regex(void *opaque) +{ + pcre_free(opaque); +} +/* }}} */ +#endif + +/* {{{ php_mb_nls_get_default_detect_order_list */ +static int php_mb_nls_get_default_detect_order_list(enum mbfl_no_language lang, enum mbfl_no_encoding **plist, size_t *plist_size) +{ + size_t i; + + *plist = (enum mbfl_no_encoding *) php_mb_default_identify_list_neut; + *plist_size = sizeof(php_mb_default_identify_list_neut) / sizeof(php_mb_default_identify_list_neut[0]); + + for (i = 0; i < sizeof(php_mb_default_identify_list) / sizeof(php_mb_default_identify_list[0]); i++) { + if (php_mb_default_identify_list[i].lang == lang) { + *plist = (enum mbfl_no_encoding *)php_mb_default_identify_list[i].list; + *plist_size = php_mb_default_identify_list[i].list_size; + return 1; + } + } + return 0; +} +/* }}} */ + +static char *php_mb_rfc1867_substring_conf(const zend_encoding *encoding, char *start, int len, char quote TSRMLS_DC) +{ + char *result = emalloc(len + 2); + char *resp = result; + int i; + + for (i = 0; i < len && start[i] != quote; ++i) { + if (start[i] == '\\' && (start[i + 1] == '\\' || (quote && start[i + 1] == quote))) { + *resp++ = start[++i]; + } else { + size_t j = php_mb_mbchar_bytes_ex(start+i, (const mbfl_encoding *)encoding); + + while (j-- > 0 && i < len) { + *resp++ = start[i++]; + } + --i; + } + } + + *resp = '\0'; + return result; +} + +static char *php_mb_rfc1867_getword(const zend_encoding *encoding, char **line, char stop TSRMLS_DC) /* {{{ */ +{ + char *pos = *line, quote; + char *res; + + while (*pos && *pos != stop) { + if ((quote = *pos) == '"' || quote == '\'') { + ++pos; + while (*pos && *pos != quote) { + if (*pos == '\\' && pos[1] && pos[1] == quote) { + pos += 2; + } else { + ++pos; + } + } + if (*pos) { + ++pos; + } + } else { + pos += php_mb_mbchar_bytes_ex(pos, (const mbfl_encoding *)encoding); + + } + } + if (*pos == '\0') { + res = estrdup(*line); + *line += strlen(*line); + return res; + } + + res = estrndup(*line, pos - *line); + + while (*pos == stop) { + pos += php_mb_mbchar_bytes_ex(pos, (const mbfl_encoding *)encoding); + } + + *line = pos; + return res; +} +/* }}} */ + +static char *php_mb_rfc1867_getword_conf(const zend_encoding *encoding, char *str TSRMLS_DC) /* {{{ */ +{ + while (*str && isspace(*(unsigned char *)str)) { + ++str; + } + + if (!*str) { + return estrdup(""); + } + + if (*str == '"' || *str == '\'') { + char quote = *str; + + str++; + return php_mb_rfc1867_substring_conf(encoding, str, strlen(str), quote TSRMLS_CC); + } else { + char *strend = str; + + while (*strend && !isspace(*(unsigned char *)strend)) { + ++strend; + } + return php_mb_rfc1867_substring_conf(encoding, str, strend - str, 0 TSRMLS_CC); + } +} +/* }}} */ + +static char *php_mb_rfc1867_basename(const zend_encoding *encoding, char *filename TSRMLS_DC) /* {{{ */ +{ + char *s, *s2; + const size_t filename_len = strlen(filename); + + /* The \ check should technically be needed for win32 systems only where + * it is a valid path separator. However, IE in all it's wisdom always sends + * the full path of the file on the user's filesystem, which means that unless + * the user does basename() they get a bogus file name. Until IE's user base drops + * to nill or problem is fixed this code must remain enabled for all systems. */ + s = php_mb_safe_strrchr_ex(filename, '\\', filename_len, (const mbfl_encoding *)encoding); + s2 = php_mb_safe_strrchr_ex(filename, '/', filename_len, (const mbfl_encoding *)encoding); + + if (s && s2) { + if (s > s2) { + return ++s; + } else { + return ++s2; + } + } else if (s) { + return ++s; + } else if (s2) { + return ++s2; + } else { + return filename; + } +} +/* }}} */ + +/* {{{ php.ini directive handler */ +/* {{{ static PHP_INI_MH(OnUpdate_mbstring_language) */ +static PHP_INI_MH(OnUpdate_mbstring_language) +{ + enum mbfl_no_language no_language; + + no_language = mbfl_name2no_language(new_value); + if (no_language == mbfl_no_language_invalid) { + MBSTRG(language) = mbfl_no_language_neutral; + return FAILURE; + } + MBSTRG(language) = no_language; + php_mb_nls_get_default_detect_order_list(no_language, &MBSTRG(default_detect_order_list), &MBSTRG(default_detect_order_list_size)); + return SUCCESS; +} +/* }}} */ + +/* {{{ static PHP_INI_MH(OnUpdate_mbstring_detect_order) */ +static PHP_INI_MH(OnUpdate_mbstring_detect_order) +{ + const mbfl_encoding **list; + size_t size; + + if (!new_value) { + if (MBSTRG(detect_order_list)) { + pefree(MBSTRG(detect_order_list), 1); + } + MBSTRG(detect_order_list) = NULL; + MBSTRG(detect_order_list_size) = 0; + return SUCCESS; + } + + if (FAILURE == php_mb_parse_encoding_list(new_value, new_value_length, &list, &size, 1 TSRMLS_CC)) { + return FAILURE; + } + + if (MBSTRG(detect_order_list)) { + pefree(MBSTRG(detect_order_list), 1); + } + MBSTRG(detect_order_list) = list; + MBSTRG(detect_order_list_size) = size; + return SUCCESS; +} +/* }}} */ + +/* {{{ static PHP_INI_MH(OnUpdate_mbstring_http_input) */ +static PHP_INI_MH(OnUpdate_mbstring_http_input) +{ + const mbfl_encoding **list; + size_t size; + + if (!new_value) { + if (MBSTRG(http_input_list)) { + pefree(MBSTRG(http_input_list), 1); + } + MBSTRG(http_input_list) = NULL; + MBSTRG(http_input_list_size) = 0; + return SUCCESS; + } + + if (FAILURE == php_mb_parse_encoding_list(new_value, new_value_length, &list, &size, 1 TSRMLS_CC)) { + return FAILURE; + } + + if (MBSTRG(http_input_list)) { + pefree(MBSTRG(http_input_list), 1); + } + MBSTRG(http_input_list) = list; + MBSTRG(http_input_list_size) = size; + + return SUCCESS; +} +/* }}} */ + +/* {{{ static PHP_INI_MH(OnUpdate_mbstring_http_output) */ +static PHP_INI_MH(OnUpdate_mbstring_http_output) +{ + const mbfl_encoding *encoding; + + if (new_value == NULL || new_value_length == 0) { + MBSTRG(http_output_encoding) = &mbfl_encoding_pass; + MBSTRG(current_http_output_encoding) = &mbfl_encoding_pass; + return SUCCESS; + } + + encoding = mbfl_name2encoding(new_value); + if (!encoding) { + MBSTRG(http_output_encoding) = &mbfl_encoding_pass; + MBSTRG(current_http_output_encoding) = &mbfl_encoding_pass; + return FAILURE; + } + + MBSTRG(http_output_encoding) = encoding; + MBSTRG(current_http_output_encoding) = encoding; + return SUCCESS; +} +/* }}} */ + +/* {{{ static _php_mb_ini_mbstring_internal_encoding_set */ +int _php_mb_ini_mbstring_internal_encoding_set(const char *new_value, uint new_value_length TSRMLS_DC) +{ + const mbfl_encoding *encoding; + + if (!new_value || new_value_length == 0 || !(encoding = mbfl_name2encoding(new_value))) { + switch (MBSTRG(language)) { + case mbfl_no_language_uni: + encoding = mbfl_no2encoding(mbfl_no_encoding_utf8); + break; + case mbfl_no_language_japanese: + encoding = mbfl_no2encoding(mbfl_no_encoding_euc_jp); + break; + case mbfl_no_language_korean: + encoding = mbfl_no2encoding(mbfl_no_encoding_euc_kr); + break; + case mbfl_no_language_simplified_chinese: + encoding = mbfl_no2encoding(mbfl_no_encoding_euc_cn); + break; + case mbfl_no_language_traditional_chinese: + encoding = mbfl_no2encoding(mbfl_no_encoding_euc_tw); + break; + case mbfl_no_language_russian: + encoding = mbfl_no2encoding(mbfl_no_encoding_koi8r); + break; + case mbfl_no_language_german: + encoding = mbfl_no2encoding(mbfl_no_encoding_8859_15); + break; + case mbfl_no_language_armenian: + encoding = mbfl_no2encoding(mbfl_no_encoding_armscii8); + break; + case mbfl_no_language_turkish: + encoding = mbfl_no2encoding(mbfl_no_encoding_8859_9); + break; + default: + encoding = mbfl_no2encoding(mbfl_no_encoding_8859_1); + break; + } + } + MBSTRG(internal_encoding) = encoding; + MBSTRG(current_internal_encoding) = encoding; +#if HAVE_MBREGEX + { + const char *enc_name = new_value; + if (FAILURE == php_mb_regex_set_default_mbctype(enc_name TSRMLS_CC)) { + /* falls back to EUC-JP if an unknown encoding name is given */ + enc_name = "EUC-JP"; + php_mb_regex_set_default_mbctype(enc_name TSRMLS_CC); + } + php_mb_regex_set_mbctype(new_value TSRMLS_CC); + } +#endif + return SUCCESS; +} +/* }}} */ + +/* {{{ static PHP_INI_MH(OnUpdate_mbstring_internal_encoding) */ +static PHP_INI_MH(OnUpdate_mbstring_internal_encoding) +{ + if (OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC) == FAILURE) { + return FAILURE; + } + if (stage == PHP_INI_STAGE_STARTUP || stage == PHP_INI_STAGE_SHUTDOWN + || stage == PHP_INI_STAGE_RUNTIME) { + return _php_mb_ini_mbstring_internal_encoding_set(new_value, new_value_length TSRMLS_CC); + } else { + /* the corresponding mbstring globals needs to be set according to the + * ini value in the later stage because it never falls back to the + * default value if 1. no value for mbstring.internal_encoding is given, + * 2. mbstring.language directive is processed in per-dir or runtime + * context and 3. call to the handler for mbstring.language is done + * after mbstring.internal_encoding is handled. */ + return SUCCESS; + } +} +/* }}} */ + +/* {{{ static PHP_INI_MH(OnUpdate_mbstring_substitute_character) */ +static PHP_INI_MH(OnUpdate_mbstring_substitute_character) +{ + int c; + char *endptr = NULL; + + if (new_value != NULL) { + if (strcasecmp("none", new_value) == 0) { + MBSTRG(filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE; + MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE; + } else if (strcasecmp("long", new_value) == 0) { + MBSTRG(filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_LONG; + MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_LONG; + } else if (strcasecmp("entity", new_value) == 0) { + MBSTRG(filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_ENTITY; + MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_ENTITY; + } else { + MBSTRG(filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR; + MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR; + if (new_value_length >0) { + c = strtol(new_value, &endptr, 0); + if (*endptr == '\0') { + MBSTRG(filter_illegal_substchar) = c; + MBSTRG(current_filter_illegal_substchar) = c; + } + } + } + } else { + MBSTRG(filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR; + MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR; + MBSTRG(filter_illegal_substchar) = 0x3f; /* '?' */ + MBSTRG(current_filter_illegal_substchar) = 0x3f; /* '?' */ + } + + return SUCCESS; +} +/* }}} */ + +/* {{{ static PHP_INI_MH(OnUpdate_mbstring_encoding_translation) */ +static PHP_INI_MH(OnUpdate_mbstring_encoding_translation) +{ + if (new_value == NULL) { + return FAILURE; + } + + OnUpdateBool(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC); + + if (MBSTRG(encoding_translation)) { + sapi_unregister_post_entry(php_post_entries TSRMLS_CC); + sapi_register_post_entries(mbstr_post_entries TSRMLS_CC); + } else { + sapi_unregister_post_entry(mbstr_post_entries TSRMLS_CC); + sapi_register_post_entries(php_post_entries TSRMLS_CC); + } + + return SUCCESS; +} +/* }}} */ + +/* {{{ static PHP_INI_MH(OnUpdate_mbstring_http_output_conv_mimetypes */ +static PHP_INI_MH(OnUpdate_mbstring_http_output_conv_mimetypes) +{ + zval tmp; + void *re = NULL; + + if (!new_value) { + new_value = entry->orig_value; + new_value_length = entry->orig_value_length; + } + php_trim(new_value, new_value_length, NULL, 0, &tmp, 3 TSRMLS_CC); + + if (Z_STRLEN(tmp) > 0) { + if (!(re = _php_mb_compile_regex(Z_STRVAL(tmp) TSRMLS_CC))) { + zval_dtor(&tmp); + return FAILURE; + } + } + + if (MBSTRG(http_output_conv_mimetypes)) { + _php_mb_free_regex(MBSTRG(http_output_conv_mimetypes)); + } + + MBSTRG(http_output_conv_mimetypes) = re; + + zval_dtor(&tmp); + return SUCCESS; +} +/* }}} */ +/* }}} */ + +/* {{{ php.ini directive registration */ +PHP_INI_BEGIN() + PHP_INI_ENTRY("mbstring.language", "neutral", PHP_INI_ALL, OnUpdate_mbstring_language) + PHP_INI_ENTRY("mbstring.detect_order", NULL, PHP_INI_ALL, OnUpdate_mbstring_detect_order) + PHP_INI_ENTRY("mbstring.http_input", "pass", PHP_INI_ALL, OnUpdate_mbstring_http_input) + PHP_INI_ENTRY("mbstring.http_output", "pass", PHP_INI_ALL, OnUpdate_mbstring_http_output) + STD_PHP_INI_ENTRY("mbstring.internal_encoding", NULL, PHP_INI_ALL, OnUpdate_mbstring_internal_encoding, internal_encoding_name, zend_mbstring_globals, mbstring_globals) + PHP_INI_ENTRY("mbstring.substitute_character", NULL, PHP_INI_ALL, OnUpdate_mbstring_substitute_character) + STD_PHP_INI_ENTRY("mbstring.func_overload", "0", + PHP_INI_SYSTEM, OnUpdateLong, func_overload, zend_mbstring_globals, mbstring_globals) + + STD_PHP_INI_BOOLEAN("mbstring.encoding_translation", "0", + PHP_INI_SYSTEM | PHP_INI_PERDIR, + OnUpdate_mbstring_encoding_translation, + encoding_translation, zend_mbstring_globals, mbstring_globals) + PHP_INI_ENTRY("mbstring.http_output_conv_mimetypes", + "^(text/|application/xhtml\\+xml)", + PHP_INI_ALL, + OnUpdate_mbstring_http_output_conv_mimetypes) + + STD_PHP_INI_BOOLEAN("mbstring.strict_detection", "0", + PHP_INI_ALL, + OnUpdateLong, + strict_detection, zend_mbstring_globals, mbstring_globals) +PHP_INI_END() +/* }}} */ + +/* {{{ module global initialize handler */ +static PHP_GINIT_FUNCTION(mbstring) +{ + mbstring_globals->language = mbfl_no_language_uni; + mbstring_globals->internal_encoding = NULL; + mbstring_globals->current_internal_encoding = mbstring_globals->internal_encoding; + mbstring_globals->http_output_encoding = &mbfl_encoding_pass; + mbstring_globals->current_http_output_encoding = &mbfl_encoding_pass; + mbstring_globals->http_input_identify = NULL; + mbstring_globals->http_input_identify_get = NULL; + mbstring_globals->http_input_identify_post = NULL; + mbstring_globals->http_input_identify_cookie = NULL; + mbstring_globals->http_input_identify_string = NULL; + mbstring_globals->http_input_list = NULL; + mbstring_globals->http_input_list_size = 0; + mbstring_globals->detect_order_list = NULL; + mbstring_globals->detect_order_list_size = 0; + mbstring_globals->current_detect_order_list = NULL; + mbstring_globals->current_detect_order_list_size = 0; + mbstring_globals->default_detect_order_list = (enum mbfl_no_encoding *) php_mb_default_identify_list_neut; + mbstring_globals->default_detect_order_list_size = sizeof(php_mb_default_identify_list_neut) / sizeof(php_mb_default_identify_list_neut[0]); + mbstring_globals->filter_illegal_mode = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR; + mbstring_globals->filter_illegal_substchar = 0x3f; /* '?' */ + mbstring_globals->current_filter_illegal_mode = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR; + mbstring_globals->current_filter_illegal_substchar = 0x3f; /* '?' */ + mbstring_globals->illegalchars = 0; + mbstring_globals->func_overload = 0; + mbstring_globals->encoding_translation = 0; + mbstring_globals->strict_detection = 0; + mbstring_globals->outconv = NULL; + mbstring_globals->http_output_conv_mimetypes = NULL; +#if HAVE_MBREGEX + mbstring_globals->mb_regex_globals = php_mb_regex_globals_alloc(TSRMLS_C); +#endif +} +/* }}} */ + +/* {{{ PHP_GSHUTDOWN_FUNCTION */ +static PHP_GSHUTDOWN_FUNCTION(mbstring) +{ + if (mbstring_globals->http_input_list) { + free(mbstring_globals->http_input_list); + } + if (mbstring_globals->detect_order_list) { + free(mbstring_globals->detect_order_list); + } + if (mbstring_globals->http_output_conv_mimetypes) { + _php_mb_free_regex(mbstring_globals->http_output_conv_mimetypes); + } +#if HAVE_MBREGEX + php_mb_regex_globals_free(mbstring_globals->mb_regex_globals TSRMLS_CC); +#endif +} +/* }}} */ + +/* {{{ PHP_MINIT_FUNCTION(mbstring) */ +PHP_MINIT_FUNCTION(mbstring) +{ + __mbfl_allocators = &_php_mb_allocators; + + REGISTER_INI_ENTRIES(); + + /* This is a global handler. Should not be set in a per-request handler. */ + sapi_register_treat_data(mbstr_treat_data TSRMLS_CC); + + /* Post handlers are stored in the thread-local context. */ + if (MBSTRG(encoding_translation)) { + sapi_register_post_entries(mbstr_post_entries TSRMLS_CC); + } + + REGISTER_LONG_CONSTANT("MB_OVERLOAD_MAIL", MB_OVERLOAD_MAIL, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("MB_OVERLOAD_STRING", MB_OVERLOAD_STRING, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("MB_OVERLOAD_REGEX", MB_OVERLOAD_REGEX, CONST_CS | CONST_PERSISTENT); + + REGISTER_LONG_CONSTANT("MB_CASE_UPPER", PHP_UNICODE_CASE_UPPER, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("MB_CASE_LOWER", PHP_UNICODE_CASE_LOWER, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("MB_CASE_TITLE", PHP_UNICODE_CASE_TITLE, CONST_CS | CONST_PERSISTENT); + +#if HAVE_MBREGEX + PHP_MINIT(mb_regex) (INIT_FUNC_ARGS_PASSTHRU); +#endif + + if (FAILURE == zend_multibyte_set_functions(&php_mb_zend_multibyte_functions TSRMLS_CC)) { + return FAILURE; + } + + php_rfc1867_set_multibyte_callbacks( + php_mb_encoding_translation, + php_mb_gpc_get_detect_order, + php_mb_gpc_set_input_encoding, + php_mb_rfc1867_getword, + php_mb_rfc1867_getword_conf, + php_mb_rfc1867_basename); + + return SUCCESS; +} +/* }}} */ + +/* {{{ PHP_MSHUTDOWN_FUNCTION(mbstring) */ +PHP_MSHUTDOWN_FUNCTION(mbstring) +{ + UNREGISTER_INI_ENTRIES(); + +#if HAVE_MBREGEX + PHP_MSHUTDOWN(mb_regex) (INIT_FUNC_ARGS_PASSTHRU); +#endif + + return SUCCESS; +} +/* }}} */ + +/* {{{ PHP_RINIT_FUNCTION(mbstring) */ +PHP_RINIT_FUNCTION(mbstring) +{ + zend_function *func, *orig; + const struct mb_overload_def *p; + + MBSTRG(current_internal_encoding) = MBSTRG(internal_encoding); + MBSTRG(current_http_output_encoding) = MBSTRG(http_output_encoding); + MBSTRG(current_filter_illegal_mode) = MBSTRG(filter_illegal_mode); + MBSTRG(current_filter_illegal_substchar) = MBSTRG(filter_illegal_substchar); + + MBSTRG(illegalchars) = 0; + + php_mb_populate_current_detect_order_list(TSRMLS_C); + + /* override original function. */ + if (MBSTRG(func_overload)){ + p = &(mb_ovld[0]); + + while (p->type > 0) { + if ((MBSTRG(func_overload) & p->type) == p->type && + zend_hash_find(EG(function_table), p->save_func, + strlen(p->save_func)+1, (void **)&orig) != SUCCESS) { + + zend_hash_find(EG(function_table), p->ovld_func, strlen(p->ovld_func)+1 , (void **)&func); + + if (zend_hash_find(EG(function_table), p->orig_func, strlen(p->orig_func)+1, (void **)&orig) != SUCCESS) { + php_error_docref("ref.mbstring" TSRMLS_CC, E_WARNING, "mbstring couldn't find function %s.", p->orig_func); + return FAILURE; + } else { + zend_hash_add(EG(function_table), p->save_func, strlen(p->save_func)+1, orig, sizeof(zend_function), NULL); + + if (zend_hash_update(EG(function_table), p->orig_func, strlen(p->orig_func)+1, func, sizeof(zend_function), + NULL) == FAILURE) { + php_error_docref("ref.mbstring" TSRMLS_CC, E_WARNING, "mbstring couldn't replace function %s.", p->orig_func); + return FAILURE; + } + } + } + p++; + } + } +#if HAVE_MBREGEX + PHP_RINIT(mb_regex) (INIT_FUNC_ARGS_PASSTHRU); +#endif + zend_multibyte_set_internal_encoding((const zend_encoding *)MBSTRG(internal_encoding) TSRMLS_CC); + + return SUCCESS; +} +/* }}} */ + +/* {{{ PHP_RSHUTDOWN_FUNCTION(mbstring) */ +PHP_RSHUTDOWN_FUNCTION(mbstring) +{ + const struct mb_overload_def *p; + zend_function *orig; + + if (MBSTRG(current_detect_order_list) != NULL) { + efree(MBSTRG(current_detect_order_list)); + MBSTRG(current_detect_order_list) = NULL; + MBSTRG(current_detect_order_list_size) = 0; + } + if (MBSTRG(outconv) != NULL) { + MBSTRG(illegalchars) += mbfl_buffer_illegalchars(MBSTRG(outconv)); + mbfl_buffer_converter_delete(MBSTRG(outconv)); + MBSTRG(outconv) = NULL; + } + + /* clear http input identification. */ + MBSTRG(http_input_identify) = NULL; + MBSTRG(http_input_identify_post) = NULL; + MBSTRG(http_input_identify_get) = NULL; + MBSTRG(http_input_identify_cookie) = NULL; + MBSTRG(http_input_identify_string) = NULL; + + /* clear overloaded function. */ + if (MBSTRG(func_overload)){ + p = &(mb_ovld[0]); + while (p->type > 0) { + if ((MBSTRG(func_overload) & p->type) == p->type && + zend_hash_find(EG(function_table), p->save_func, + strlen(p->save_func)+1, (void **)&orig) == SUCCESS) { + + zend_hash_update(EG(function_table), p->orig_func, strlen(p->orig_func)+1, orig, sizeof(zend_function), NULL); + zend_hash_del(EG(function_table), p->save_func, strlen(p->save_func)+1); + } + p++; + } + } + +#if HAVE_MBREGEX + PHP_RSHUTDOWN(mb_regex) (INIT_FUNC_ARGS_PASSTHRU); +#endif + + return SUCCESS; +} +/* }}} */ + +/* {{{ PHP_MINFO_FUNCTION(mbstring) */ +PHP_MINFO_FUNCTION(mbstring) +{ + php_info_print_table_start(); + php_info_print_table_row(2, "Multibyte Support", "enabled"); + php_info_print_table_row(2, "Multibyte string engine", "libmbfl"); + php_info_print_table_row(2, "HTTP input encoding translation", MBSTRG(encoding_translation) ? "enabled": "disabled"); + { + char tmp[256]; + snprintf(tmp, sizeof(tmp), "%d.%d.%d", MBFL_VERSION_MAJOR, MBFL_VERSION_MINOR, MBFL_VERSION_TEENY); + php_info_print_table_row(2, "libmbfl version", tmp); + } + php_info_print_table_end(); + + php_info_print_table_start(); + 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."); + php_info_print_table_end(); + +#if HAVE_MBREGEX + PHP_MINFO(mb_regex)(ZEND_MODULE_INFO_FUNC_ARGS_PASSTHRU); +#endif + + DISPLAY_INI_ENTRIES(); +} +/* }}} */ + +/* {{{ proto string mb_language([string language]) + Sets the current language or Returns the current language as a string */ +PHP_FUNCTION(mb_language) +{ + char *name = NULL; + int name_len = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name, &name_len) == FAILURE) { + return; + } + if (name == NULL) { + RETVAL_STRING((char *)mbfl_no_language2name(MBSTRG(language)), 1); + } else { + if (FAILURE == zend_alter_ini_entry( + "mbstring.language", sizeof("mbstring.language"), + name, name_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown language \"%s\"", name); + RETVAL_FALSE; + } else { + RETVAL_TRUE; + } + } +} +/* }}} */ + +/* {{{ proto string mb_internal_encoding([string encoding]) + Sets the current internal encoding or Returns the current internal encoding as a string */ +PHP_FUNCTION(mb_internal_encoding) +{ + const char *name = NULL; + int name_len; + const mbfl_encoding *encoding; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name, &name_len) == FAILURE) { + RETURN_FALSE; + } + if (name == NULL) { + name = MBSTRG(current_internal_encoding) ? MBSTRG(current_internal_encoding)->name: NULL; + if (name != NULL) { + RETURN_STRING(name, 1); + } else { + RETURN_FALSE; + } + } else { + encoding = mbfl_name2encoding(name); + if (!encoding) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", name); + RETURN_FALSE; + } else { + MBSTRG(current_internal_encoding) = encoding; + RETURN_TRUE; + } + } +} +/* }}} */ + +/* {{{ proto mixed mb_http_input([string type]) + Returns the input encoding */ +PHP_FUNCTION(mb_http_input) +{ + char *typ = NULL; + int typ_len; + int retname; + char *list, *temp; + const mbfl_encoding *result = NULL; + + retname = 1; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &typ, &typ_len) == FAILURE) { + RETURN_FALSE; + } + if (typ == NULL) { + result = MBSTRG(http_input_identify); + } else { + switch (*typ) { + case 'G': + case 'g': + result = MBSTRG(http_input_identify_get); + break; + case 'P': + case 'p': + result = MBSTRG(http_input_identify_post); + break; + case 'C': + case 'c': + result = MBSTRG(http_input_identify_cookie); + break; + case 'S': + case 's': + result = MBSTRG(http_input_identify_string); + break; + case 'I': + case 'i': + { + const mbfl_encoding **entry = MBSTRG(http_input_list); + const size_t n = MBSTRG(http_input_list_size); + size_t i; + array_init(return_value); + for (i = 0; i < n; i++) { + add_next_index_string(return_value, (*entry)->name, 1); + entry++; + } + retname = 0; + } + break; + case 'L': + case 'l': + { + const mbfl_encoding **entry = MBSTRG(http_input_list); + const size_t n = MBSTRG(http_input_list_size); + size_t i; + list = NULL; + for (i = 0; i < n; i++) { + if (list) { + temp = list; + spprintf(&list, 0, "%s,%s", temp, (*entry)->name); + efree(temp); + if (!list) { + break; + } + } else { + list = estrdup((*entry)->name); + } + entry++; + } + } + if (!list) { + RETURN_FALSE; + } + RETVAL_STRING(list, 0); + retname = 0; + break; + default: + result = MBSTRG(http_input_identify); + break; + } + } + + if (retname) { + if (result) { + RETVAL_STRING(result->name, 1); + } else { + RETVAL_FALSE; + } + } +} +/* }}} */ + +/* {{{ proto string mb_http_output([string encoding]) + Sets the current output_encoding or returns the current output_encoding as a string */ +PHP_FUNCTION(mb_http_output) +{ + const char *name = NULL; + int name_len; + const mbfl_encoding *encoding; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", (char **)&name, &name_len) == FAILURE) { + RETURN_FALSE; + } + + if (name == NULL) { + name = MBSTRG(current_http_output_encoding) ? MBSTRG(current_http_output_encoding)->name: NULL; + if (name != NULL) { + RETURN_STRING(name, 1); + } else { + RETURN_FALSE; + } + } else { + encoding = mbfl_name2encoding(name); + if (!encoding) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", name); + RETURN_FALSE; + } else { + MBSTRG(current_http_output_encoding) = encoding; + RETURN_TRUE; + } + } +} +/* }}} */ + +/* {{{ proto bool|array mb_detect_order([mixed encoding-list]) + Sets the current detect_order or Return the current detect_order as a array */ +PHP_FUNCTION(mb_detect_order) +{ + zval **arg1 = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|Z", &arg1) == FAILURE) { + return; + } + + if (!arg1) { + size_t i; + size_t n = MBSTRG(current_detect_order_list_size); + const mbfl_encoding **entry = MBSTRG(current_detect_order_list); + array_init(return_value); + for (i = 0; i < n; i++) { + add_next_index_string(return_value, (*entry)->name, 1); + entry++; + } + } else { + const mbfl_encoding **list = NULL; + size_t size = 0; + switch (Z_TYPE_PP(arg1)) { + case IS_ARRAY: + if (FAILURE == php_mb_parse_encoding_array(*arg1, &list, &size, 0 TSRMLS_CC)) { + if (list) { + efree(list); + } + RETURN_FALSE; + } + break; + default: + convert_to_string_ex(arg1); + if (FAILURE == php_mb_parse_encoding_list(Z_STRVAL_PP(arg1), Z_STRLEN_PP(arg1), &list, &size, 0 TSRMLS_CC)) { + if (list) { + efree(list); + } + RETURN_FALSE; + } + break; + } + + if (list == NULL) { + RETURN_FALSE; + } + + if (MBSTRG(current_detect_order_list)) { + efree(MBSTRG(current_detect_order_list)); + } + MBSTRG(current_detect_order_list) = list; + MBSTRG(current_detect_order_list_size) = size; + RETURN_TRUE; + } +} +/* }}} */ + +/* {{{ proto mixed mb_substitute_character([mixed substchar]) + Sets the current substitute_character or returns the current substitute_character */ +PHP_FUNCTION(mb_substitute_character) +{ + zval **arg1 = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|Z", &arg1) == FAILURE) { + return; + } + + if (!arg1) { + if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE) { + RETURN_STRING("none", 1); + } else if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_LONG) { + RETURN_STRING("long", 1); + } else if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_ENTITY) { + RETURN_STRING("entity", 1); + } else { + RETURN_LONG(MBSTRG(current_filter_illegal_substchar)); + } + } else { + RETVAL_TRUE; + + switch (Z_TYPE_PP(arg1)) { + case IS_STRING: + if (strncasecmp("none", Z_STRVAL_PP(arg1), Z_STRLEN_PP(arg1)) == 0) { + MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE; + } else if (strncasecmp("long", Z_STRVAL_PP(arg1), Z_STRLEN_PP(arg1)) == 0) { + MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_LONG; + } else if (strncasecmp("entity", Z_STRVAL_PP(arg1), Z_STRLEN_PP(arg1)) == 0) { + MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_ENTITY; + } else { + convert_to_long_ex(arg1); + + if (Z_LVAL_PP(arg1) < 0xffff && Z_LVAL_PP(arg1) > 0x0) { + MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR; + MBSTRG(current_filter_illegal_substchar) = Z_LVAL_PP(arg1); + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown character."); + RETURN_FALSE; + } + } + break; + default: + convert_to_long_ex(arg1); + if (Z_LVAL_PP(arg1) < 0xffff && Z_LVAL_PP(arg1) > 0x0) { + MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR; + MBSTRG(current_filter_illegal_substchar) = Z_LVAL_PP(arg1); + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown character."); + RETURN_FALSE; + } + break; + } + } +} +/* }}} */ + +/* {{{ proto string mb_preferred_mime_name(string encoding) + Return the preferred MIME name (charset) as a string */ +PHP_FUNCTION(mb_preferred_mime_name) +{ + enum mbfl_no_encoding no_encoding; + char *name = NULL; + int name_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) { + return; + } else { + no_encoding = mbfl_name2no_encoding(name); + if (no_encoding == mbfl_no_encoding_invalid) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", name); + RETVAL_FALSE; + } else { + const char *preferred_name = mbfl_no2preferred_mime_name(no_encoding); + if (preferred_name == NULL || *preferred_name == '\0') { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "No MIME preferred name corresponding to \"%s\"", name); + RETVAL_FALSE; + } else { + RETVAL_STRING((char *)preferred_name, 1); + } + } + } +} +/* }}} */ + +#define IS_SJIS1(c) ((((c)>=0x81 && (c)<=0x9f) || ((c)>=0xe0 && (c)<=0xf5)) ? 1 : 0) +#define IS_SJIS2(c) ((((c)>=0x40 && (c)<=0x7e) || ((c)>=0x80 && (c)<=0xfc)) ? 1 : 0) + +/* {{{ proto bool mb_parse_str(string encoded_string [, array result]) + Parses GET/POST/COOKIE data and sets global variables */ +PHP_FUNCTION(mb_parse_str) +{ + zval *track_vars_array = NULL; + char *encstr = NULL; + int encstr_len; + php_mb_encoding_handler_info_t info; + const mbfl_encoding *detected; + + track_vars_array = NULL; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z", &encstr, &encstr_len, &track_vars_array) == FAILURE) { + return; + } + + if (track_vars_array != NULL) { + /* Clear out the array */ + zval_dtor(track_vars_array); + array_init(track_vars_array); + } + + encstr = estrndup(encstr, encstr_len); + + info.data_type = PARSE_STRING; + info.separator = PG(arg_separator).input; + info.report_errors = 1; + info.to_encoding = MBSTRG(current_internal_encoding); + info.to_language = MBSTRG(language); + info.from_encodings = MBSTRG(http_input_list); + info.num_from_encodings = MBSTRG(http_input_list_size); + info.from_language = MBSTRG(language); + + if (track_vars_array != NULL) { + detected = _php_mb_encoding_handler_ex(&info, track_vars_array, encstr TSRMLS_CC); + } else { + zval tmp; + if (!EG(active_symbol_table)) { + zend_rebuild_symbol_table(TSRMLS_C); + } + Z_ARRVAL(tmp) = EG(active_symbol_table); + detected = _php_mb_encoding_handler_ex(&info, &tmp, encstr TSRMLS_CC); + } + + MBSTRG(http_input_identify) = detected; + + RETVAL_BOOL(detected); + + if (encstr != NULL) efree(encstr); +} +/* }}} */ + +/* {{{ proto string mb_output_handler(string contents, int status) + Returns string in output buffer converted to the http_output encoding */ +PHP_FUNCTION(mb_output_handler) +{ + char *arg_string; + int arg_string_len; + long arg_status; + mbfl_string string, result; + const char *charset; + char *p; + const mbfl_encoding *encoding; + int last_feed, len; + unsigned char send_text_mimetype = 0; + char *s, *mimetype = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &arg_string, &arg_string_len, &arg_status) == FAILURE) { + return; + } + + encoding = MBSTRG(current_http_output_encoding); + + /* start phase only */ + if ((arg_status & PHP_OUTPUT_HANDLER_START) != 0) { + /* delete the converter just in case. */ + if (MBSTRG(outconv)) { + MBSTRG(illegalchars) += mbfl_buffer_illegalchars(MBSTRG(outconv)); + mbfl_buffer_converter_delete(MBSTRG(outconv)); + MBSTRG(outconv) = NULL; + } + if (encoding == &mbfl_encoding_pass) { + RETURN_STRINGL(arg_string, arg_string_len, 1); + } + + /* analyze mime type */ + if (SG(sapi_headers).mimetype && + _php_mb_match_regex( + MBSTRG(http_output_conv_mimetypes), + SG(sapi_headers).mimetype, + strlen(SG(sapi_headers).mimetype))) { + if ((s = strchr(SG(sapi_headers).mimetype,';')) == NULL){ + mimetype = estrdup(SG(sapi_headers).mimetype); + } else { + mimetype = estrndup(SG(sapi_headers).mimetype,s-SG(sapi_headers).mimetype); + } + send_text_mimetype = 1; + } else if (SG(sapi_headers).send_default_content_type) { + mimetype = SG(default_mimetype) ? SG(default_mimetype) : SAPI_DEFAULT_MIMETYPE; + } + + /* if content-type is not yet set, set it and activate the converter */ + if (SG(sapi_headers).send_default_content_type || send_text_mimetype) { + charset = encoding->mime_name; + if (charset) { + len = spprintf( &p, 0, "Content-Type: %s; charset=%s", mimetype, charset ); + if (sapi_add_header(p, len, 0) != FAILURE) { + SG(sapi_headers).send_default_content_type = 0; + } + } + /* activate the converter */ + MBSTRG(outconv) = mbfl_buffer_converter_new2(MBSTRG(current_internal_encoding), encoding, 0); + if (send_text_mimetype){ + efree(mimetype); + } + } + } + + /* just return if the converter is not activated. */ + if (MBSTRG(outconv) == NULL) { + RETURN_STRINGL(arg_string, arg_string_len, 1); + } + + /* flag */ + last_feed = ((arg_status & PHP_OUTPUT_HANDLER_END) != 0); + /* mode */ + mbfl_buffer_converter_illegal_mode(MBSTRG(outconv), MBSTRG(current_filter_illegal_mode)); + mbfl_buffer_converter_illegal_substchar(MBSTRG(outconv), MBSTRG(current_filter_illegal_substchar)); + + /* feed the string */ + mbfl_string_init(&string); + string.no_language = MBSTRG(language); + string.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; + string.val = (unsigned char *)arg_string; + string.len = arg_string_len; + mbfl_buffer_converter_feed(MBSTRG(outconv), &string); + if (last_feed) { + mbfl_buffer_converter_flush(MBSTRG(outconv)); + } + /* get the converter output, and return it */ + mbfl_buffer_converter_result(MBSTRG(outconv), &result); + RETVAL_STRINGL((char *)result.val, result.len, 0); /* the string is already strdup()'ed */ + + /* delete the converter if it is the last feed. */ + if (last_feed) { + MBSTRG(illegalchars) += mbfl_buffer_illegalchars(MBSTRG(outconv)); + mbfl_buffer_converter_delete(MBSTRG(outconv)); + MBSTRG(outconv) = NULL; + } +} +/* }}} */ + +/* {{{ proto int mb_strlen(string str [, string encoding]) + Get character numbers of a string */ +PHP_FUNCTION(mb_strlen) +{ + int n; + mbfl_string string; + char *enc_name = NULL; + int enc_name_len; + + mbfl_string_init(&string); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", (char **)&string.val, &string.len, &enc_name, &enc_name_len) == FAILURE) { + RETURN_FALSE; + } + + string.no_language = MBSTRG(language); + if (enc_name == NULL) { + string.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; + } else { + string.no_encoding = mbfl_name2no_encoding(enc_name); + if (string.no_encoding == mbfl_no_encoding_invalid) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", enc_name); + RETURN_FALSE; + } + } + + n = mbfl_strlen(&string); + if (n >= 0) { + RETVAL_LONG(n); + } else { + RETVAL_FALSE; + } +} +/* }}} */ + +/* {{{ proto int mb_strpos(string haystack, string needle [, int offset [, string encoding]]) + Find position of first occurrence of a string within another */ +PHP_FUNCTION(mb_strpos) +{ + int n, reverse = 0; + long offset; + mbfl_string haystack, needle; + char *enc_name = NULL; + int enc_name_len; + + mbfl_string_init(&haystack); + mbfl_string_init(&needle); + haystack.no_language = MBSTRG(language); + haystack.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; + needle.no_language = MBSTRG(language); + needle.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; + offset = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ls", (char **)&haystack.val, &haystack.len, (char **)&needle.val, &needle.len, &offset, &enc_name, &enc_name_len) == FAILURE) { + RETURN_FALSE; + } + + if (enc_name != NULL) { + haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(enc_name); + if (haystack.no_encoding == mbfl_no_encoding_invalid) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", enc_name); + RETURN_FALSE; + } + } + + if (offset < 0 || offset > mbfl_strlen(&haystack)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset not contained in string"); + RETURN_FALSE; + } + if (needle.len == 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter"); + RETURN_FALSE; + } + + n = mbfl_strpos(&haystack, &needle, offset, reverse); + if (n >= 0) { + RETVAL_LONG(n); + } else { + switch (-n) { + case 1: + break; + case 2: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Needle has not positive length"); + break; + case 4: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding or conversion error"); + break; + case 8: + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Argument is empty"); + break; + default: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown error in mb_strpos"); + break; + } + RETVAL_FALSE; + } +} +/* }}} */ + +/* {{{ proto int mb_strrpos(string haystack, string needle [, int offset [, string encoding]]) + Find position of last occurrence of a string within another */ +PHP_FUNCTION(mb_strrpos) +{ + int n; + mbfl_string haystack, needle; + char *enc_name = NULL; + int enc_name_len; + zval **zoffset = NULL; + long offset = 0, str_flg; + char *enc_name2 = NULL; + int enc_name_len2; + + mbfl_string_init(&haystack); + mbfl_string_init(&needle); + haystack.no_language = MBSTRG(language); + haystack.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; + needle.no_language = MBSTRG(language); + needle.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|Zs", (char **)&haystack.val, &haystack.len, (char **)&needle.val, &needle.len, &zoffset, &enc_name, &enc_name_len) == FAILURE) { + RETURN_FALSE; + } + + if (zoffset) { + if (Z_TYPE_PP(zoffset) == IS_STRING) { + enc_name2 = Z_STRVAL_PP(zoffset); + enc_name_len2 = Z_STRLEN_PP(zoffset); + str_flg = 1; + + if (enc_name2 != NULL) { + switch (*enc_name2) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case ' ': + case '-': + case '.': + break; + default : + str_flg = 0; + break; + } + } + + if (str_flg) { + convert_to_long_ex(zoffset); + offset = Z_LVAL_PP(zoffset); + } else { + enc_name = enc_name2; + enc_name_len = enc_name_len2; + } + } else { + convert_to_long_ex(zoffset); + offset = Z_LVAL_PP(zoffset); + } + } + + if (enc_name != NULL) { + haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(enc_name); + if (haystack.no_encoding == mbfl_no_encoding_invalid) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", enc_name); + RETURN_FALSE; + } + } + + if (haystack.len <= 0) { + RETURN_FALSE; + } + if (needle.len <= 0) { + RETURN_FALSE; + } + + { + int haystack_char_len = mbfl_strlen(&haystack); + if ((offset > 0 && offset > haystack_char_len) || + (offset < 0 && -offset > haystack_char_len)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string"); + RETURN_FALSE; + } + } + + n = mbfl_strpos(&haystack, &needle, offset, 1); + if (n >= 0) { + RETVAL_LONG(n); + } else { + RETVAL_FALSE; + } +} +/* }}} */ + +/* {{{ proto int mb_stripos(string haystack, string needle [, int offset [, string encoding]]) + Finds position of first occurrence of a string within another, case insensitive */ +PHP_FUNCTION(mb_stripos) +{ + int n; + long offset; + mbfl_string haystack, needle; + const char *from_encoding = MBSTRG(current_internal_encoding)->mime_name; + int from_encoding_len; + n = -1; + offset = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ls", (char **)&haystack.val, (int *)&haystack.len, (char **)&needle.val, (int *)&needle.len, &offset, &from_encoding, &from_encoding_len) == FAILURE) { + RETURN_FALSE; + } + if (needle.len == 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter"); + RETURN_FALSE; + } + n = php_mb_stripos(0, (char *)haystack.val, haystack.len, (char *)needle.val, needle.len, offset, from_encoding TSRMLS_CC); + + if (n >= 0) { + RETVAL_LONG(n); + } else { + RETVAL_FALSE; + } +} +/* }}} */ + +/* {{{ proto int mb_strripos(string haystack, string needle [, int offset [, string encoding]]) + Finds position of last occurrence of a string within another, case insensitive */ +PHP_FUNCTION(mb_strripos) +{ + int n; + long offset; + mbfl_string haystack, needle; + const char *from_encoding = MBSTRG(current_internal_encoding)->mime_name; + int from_encoding_len; + n = -1; + offset = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ls", (char **)&haystack.val, (int *)&haystack.len, (char **)&needle.val, (int *)&needle.len, &offset, &from_encoding, &from_encoding_len) == FAILURE) { + RETURN_FALSE; + } + + n = php_mb_stripos(1, (char *)haystack.val, haystack.len, (char *)needle.val, needle.len, offset, from_encoding TSRMLS_CC); + + if (n >= 0) { + RETVAL_LONG(n); + } else { + RETVAL_FALSE; + } +} +/* }}} */ + +/* {{{ proto string mb_strstr(string haystack, string needle[, bool part[, string encoding]]) + Finds first occurrence of a string within another */ +PHP_FUNCTION(mb_strstr) +{ + int n, len, mblen; + mbfl_string haystack, needle, result, *ret = NULL; + char *enc_name = NULL; + int enc_name_len; + zend_bool part = 0; + + mbfl_string_init(&haystack); + mbfl_string_init(&needle); + haystack.no_language = MBSTRG(language); + haystack.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; + needle.no_language = MBSTRG(language); + needle.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|bs", (char **)&haystack.val, (int *)&haystack.len, (char **)&needle.val, (int *)&needle.len, &part, &enc_name, &enc_name_len) == FAILURE) { + RETURN_FALSE; + } + + if (enc_name != NULL) { + haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(enc_name); + if (haystack.no_encoding == mbfl_no_encoding_invalid) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", enc_name); + RETURN_FALSE; + } + } + + if (needle.len <= 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter"); + RETURN_FALSE; + } + n = mbfl_strpos(&haystack, &needle, 0, 0); + if (n >= 0) { + mblen = mbfl_strlen(&haystack); + if (part) { + ret = mbfl_substr(&haystack, &result, 0, n); + if (ret != NULL) { + RETVAL_STRINGL((char *)ret->val, ret->len, 0); + } else { + RETVAL_FALSE; + } + } else { + len = (mblen - n); + ret = mbfl_substr(&haystack, &result, n, len); + if (ret != NULL) { + RETVAL_STRINGL((char *)ret->val, ret->len, 0); + } else { + RETVAL_FALSE; + } + } + } else { + RETVAL_FALSE; + } +} +/* }}} */ + +/* {{{ proto string mb_strrchr(string haystack, string needle[, bool part[, string encoding]]) + Finds the last occurrence of a character in a string within another */ +PHP_FUNCTION(mb_strrchr) +{ + int n, len, mblen; + mbfl_string haystack, needle, result, *ret = NULL; + char *enc_name = NULL; + int enc_name_len; + zend_bool part = 0; + + mbfl_string_init(&haystack); + mbfl_string_init(&needle); + haystack.no_language = MBSTRG(language); + haystack.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; + needle.no_language = MBSTRG(language); + needle.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|bs", (char **)&haystack.val, &haystack.len, (char **)&needle.val, &needle.len, &part, &enc_name, &enc_name_len) == FAILURE) { + RETURN_FALSE; + } + + if (enc_name != NULL) { + haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(enc_name); + if (haystack.no_encoding == mbfl_no_encoding_invalid) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", enc_name); + RETURN_FALSE; + } + } + + if (haystack.len <= 0) { + RETURN_FALSE; + } + if (needle.len <= 0) { + RETURN_FALSE; + } + n = mbfl_strpos(&haystack, &needle, 0, 1); + if (n >= 0) { + mblen = mbfl_strlen(&haystack); + if (part) { + ret = mbfl_substr(&haystack, &result, 0, n); + if (ret != NULL) { + RETVAL_STRINGL((char *)ret->val, ret->len, 0); + } else { + RETVAL_FALSE; + } + } else { + len = (mblen - n); + ret = mbfl_substr(&haystack, &result, n, len); + if (ret != NULL) { + RETVAL_STRINGL((char *)ret->val, ret->len, 0); + } else { + RETVAL_FALSE; + } + } + } else { + RETVAL_FALSE; + } +} +/* }}} */ + +/* {{{ proto string mb_stristr(string haystack, string needle[, bool part[, string encoding]]) + Finds first occurrence of a string within another, case insensitive */ +PHP_FUNCTION(mb_stristr) +{ + zend_bool part = 0; + unsigned int from_encoding_len, len, mblen; + int n; + mbfl_string haystack, needle, result, *ret = NULL; + const char *from_encoding = MBSTRG(current_internal_encoding)->mime_name; + mbfl_string_init(&haystack); + mbfl_string_init(&needle); + haystack.no_language = MBSTRG(language); + haystack.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; + needle.no_language = MBSTRG(language); + needle.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; + + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|bs", (char **)&haystack.val, &haystack.len, (char **)&needle.val, &needle.len, &part, &from_encoding, &from_encoding_len) == FAILURE) { + RETURN_FALSE; + } + + if (!needle.len) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter"); + RETURN_FALSE; + } + + haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(from_encoding); + if (haystack.no_encoding == mbfl_no_encoding_invalid) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", from_encoding); + RETURN_FALSE; + } + + n = php_mb_stripos(0, (char *)haystack.val, haystack.len, (char *)needle.val, needle.len, 0, from_encoding TSRMLS_CC); + + if (n <0) { + RETURN_FALSE; + } + + mblen = mbfl_strlen(&haystack); + + if (part) { + ret = mbfl_substr(&haystack, &result, 0, n); + if (ret != NULL) { + RETVAL_STRINGL((char *)ret->val, ret->len, 0); + } else { + RETVAL_FALSE; + } + } else { + len = (mblen - n); + ret = mbfl_substr(&haystack, &result, n, len); + if (ret != NULL) { + RETVAL_STRINGL((char *)ret->val, ret->len, 0); + } else { + RETVAL_FALSE; + } + } +} +/* }}} */ + +/* {{{ proto string mb_strrichr(string haystack, string needle[, bool part[, string encoding]]) + Finds the last occurrence of a character in a string within another, case insensitive */ +PHP_FUNCTION(mb_strrichr) +{ + zend_bool part = 0; + int n, from_encoding_len, len, mblen; + mbfl_string haystack, needle, result, *ret = NULL; + const char *from_encoding = MBSTRG(current_internal_encoding)->name; + mbfl_string_init(&haystack); + mbfl_string_init(&needle); + haystack.no_language = MBSTRG(language); + haystack.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; + needle.no_language = MBSTRG(language); + needle.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; + + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|bs", (char **)&haystack.val, &haystack.len, (char **)&needle.val, &needle.len, &part, &from_encoding, &from_encoding_len) == FAILURE) { + RETURN_FALSE; + } + + haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(from_encoding); + if (haystack.no_encoding == mbfl_no_encoding_invalid) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", from_encoding); + RETURN_FALSE; + } + + n = php_mb_stripos(1, (char *)haystack.val, haystack.len, (char *)needle.val, needle.len, 0, from_encoding TSRMLS_CC); + + if (n <0) { + RETURN_FALSE; + } + + mblen = mbfl_strlen(&haystack); + + if (part) { + ret = mbfl_substr(&haystack, &result, 0, n); + if (ret != NULL) { + RETVAL_STRINGL((char *)ret->val, ret->len, 0); + } else { + RETVAL_FALSE; + } + } else { + len = (mblen - n); + ret = mbfl_substr(&haystack, &result, n, len); + if (ret != NULL) { + RETVAL_STRINGL((char *)ret->val, ret->len, 0); + } else { + RETVAL_FALSE; + } + } +} +/* }}} */ + +/* {{{ proto int mb_substr_count(string haystack, string needle [, string encoding]) + Count the number of substring occurrences */ +PHP_FUNCTION(mb_substr_count) +{ + int n; + mbfl_string haystack, needle; + char *enc_name = NULL; + int enc_name_len; + + mbfl_string_init(&haystack); + mbfl_string_init(&needle); + haystack.no_language = MBSTRG(language); + haystack.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; + needle.no_language = MBSTRG(language); + needle.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s", (char **)&haystack.val, &haystack.len, (char **)&needle.val, &needle.len, &enc_name, &enc_name_len) == FAILURE) { + return; + } + + if (enc_name != NULL) { + haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(enc_name); + if (haystack.no_encoding == mbfl_no_encoding_invalid) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", enc_name); + RETURN_FALSE; + } + } + + if (needle.len <= 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty substring"); + RETURN_FALSE; + } + + n = mbfl_substr_count(&haystack, &needle); + if (n >= 0) { + RETVAL_LONG(n); + } else { + RETVAL_FALSE; + } +} +/* }}} */ + +/* {{{ proto string mb_substr(string str, int start [, int length [, string encoding]]) + Returns part of a string */ +PHP_FUNCTION(mb_substr) +{ + size_t argc = ZEND_NUM_ARGS(); + char *str, *encoding; + long from, len; + int mblen, str_len, encoding_len; + zval **z_len = NULL; + mbfl_string string, result, *ret; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|Zs", &str, &str_len, &from, &z_len, &encoding, &encoding_len) == FAILURE) { + return; + } + + mbfl_string_init(&string); + string.no_language = MBSTRG(language); + string.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; + + if (argc == 4) { + string.no_encoding = mbfl_name2no_encoding(encoding); + if (string.no_encoding == mbfl_no_encoding_invalid) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", encoding); + RETURN_FALSE; + } + } + + string.val = (unsigned char *)str; + string.len = str_len; + + if (argc < 3 || Z_TYPE_PP(z_len) == IS_NULL) { + len = str_len; + } else { + convert_to_long_ex(z_len); + len = Z_LVAL_PP(z_len); + } + + /* measures length */ + mblen = 0; + if (from < 0 || len < 0) { + mblen = mbfl_strlen(&string); + } + + /* if "from" position is negative, count start position from the end + * of the string + */ + if (from < 0) { + from = mblen + from; + if (from < 0) { + from = 0; + } + } + + /* if "length" position is negative, set it to the length + * needed to stop that many chars from the end of the string + */ + if (len < 0) { + len = (mblen - from) + len; + if (len < 0) { + len = 0; + } + } + + if (((MBSTRG(func_overload) & MB_OVERLOAD_STRING) == MB_OVERLOAD_STRING) + && (from >= mbfl_strlen(&string))) { + RETURN_FALSE; + } + + ret = mbfl_substr(&string, &result, from, len); + if (NULL == ret) { + RETURN_FALSE; + } + + RETURN_STRINGL((char *)ret->val, ret->len, 0); /* the string is already strdup()'ed */ +} +/* }}} */ + +/* {{{ proto string mb_strcut(string str, int start [, int length [, string encoding]]) + Returns part of a string */ +PHP_FUNCTION(mb_strcut) +{ + size_t argc = ZEND_NUM_ARGS(); + char *encoding; + long from, len; + int encoding_len; + zval **z_len = NULL; + mbfl_string string, result, *ret; + + mbfl_string_init(&string); + string.no_language = MBSTRG(language); + string.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|Zs", (char **)&string.val, (int **)&string.len, &from, &z_len, &encoding, &encoding_len) == FAILURE) { + return; + } + + if (argc == 4) { + string.no_encoding = mbfl_name2no_encoding(encoding); + if (string.no_encoding == mbfl_no_encoding_invalid) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", encoding); + RETURN_FALSE; + } + } + + if (argc < 3 || Z_TYPE_PP(z_len) == IS_NULL) { + len = string.len; + } else { + convert_to_long_ex(z_len); + len = Z_LVAL_PP(z_len); + } + + /* if "from" position is negative, count start position from the end + * of the string + */ + if (from < 0) { + from = string.len + from; + if (from < 0) { + from = 0; + } + } + + /* if "length" position is negative, set it to the length + * needed to stop that many chars from the end of the string + */ + if (len < 0) { + len = (string.len - from) + len; + if (len < 0) { + len = 0; + } + } + + if ((unsigned int)from > string.len) { + RETURN_FALSE; + } + + ret = mbfl_strcut(&string, &result, from, len); + if (ret == NULL) { + RETURN_FALSE; + } + + RETURN_STRINGL((char *)ret->val, ret->len, 0); /* the string is already strdup()'ed */ +} +/* }}} */ + +/* {{{ proto int mb_strwidth(string str [, string encoding]) + Gets terminal width of a string */ +PHP_FUNCTION(mb_strwidth) +{ + int n; + mbfl_string string; + char *enc_name = NULL; + int enc_name_len; + + mbfl_string_init(&string); + + string.no_language = MBSTRG(language); + string.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", (char **)&string.val, &string.len, &enc_name, &enc_name_len) == FAILURE) { + return; + } + + if (enc_name != NULL) { + string.no_encoding = mbfl_name2no_encoding(enc_name); + if (string.no_encoding == mbfl_no_encoding_invalid) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", enc_name); + RETURN_FALSE; + } + } + + n = mbfl_strwidth(&string); + if (n >= 0) { + RETVAL_LONG(n); + } else { + RETVAL_FALSE; + } +} +/* }}} */ + +/* {{{ proto string mb_strimwidth(string str, int start, int width [, string trimmarker [, string encoding]]) + Trim the string in terminal width */ +PHP_FUNCTION(mb_strimwidth) +{ + char *str, *trimmarker, *encoding; + long from, width; + int str_len, trimmarker_len, encoding_len; + mbfl_string string, result, marker, *ret; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sll|ss", &str, &str_len, &from, &width, &trimmarker, &trimmarker_len, &encoding, &encoding_len) == FAILURE) { + return; + } + + mbfl_string_init(&string); + mbfl_string_init(&marker); + string.no_language = MBSTRG(language); + string.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; + marker.no_language = MBSTRG(language); + marker.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; + marker.val = NULL; + marker.len = 0; + + if (ZEND_NUM_ARGS() == 5) { + string.no_encoding = marker.no_encoding = mbfl_name2no_encoding(encoding); + if (string.no_encoding == mbfl_no_encoding_invalid) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", encoding); + RETURN_FALSE; + } + } + + string.val = (unsigned char *)str; + string.len = str_len; + + if (from < 0 || from > str_len) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Start position is out of range"); + RETURN_FALSE; + } + + if (width < 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Width is negative value"); + RETURN_FALSE; + } + + if (ZEND_NUM_ARGS() >= 4) { + marker.val = (unsigned char *)trimmarker; + marker.len = trimmarker_len; + } + + ret = mbfl_strimwidth(&string, &marker, &result, from, width); + + if (ret == NULL) { + RETURN_FALSE; + } + + RETVAL_STRINGL((char *)ret->val, ret->len, 0); /* the string is already strdup()'ed */ +} +/* }}} */ + +/* {{{ MBSTRING_API char *php_mb_convert_encoding() */ +MBSTRING_API char * php_mb_convert_encoding(const char *input, size_t length, const char *_to_encoding, const char *_from_encodings, size_t *output_len TSRMLS_DC) +{ + mbfl_string string, result, *ret; + const mbfl_encoding *from_encoding, *to_encoding; + mbfl_buffer_converter *convd; + size_t size; + const mbfl_encoding **list; + char *output=NULL; + + if (output_len) { + *output_len = 0; + } + if (!input) { + return NULL; + } + /* new encoding */ + if (_to_encoding && strlen(_to_encoding)) { + to_encoding = mbfl_name2encoding(_to_encoding); + if (!to_encoding) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", _to_encoding); + return NULL; + } + } else { + to_encoding = MBSTRG(current_internal_encoding); + } + + /* initialize string */ + mbfl_string_init(&string); + mbfl_string_init(&result); + from_encoding = MBSTRG(current_internal_encoding); + string.no_encoding = from_encoding->no_encoding; + string.no_language = MBSTRG(language); + string.val = (unsigned char *)input; + string.len = length; + + /* pre-conversion encoding */ + if (_from_encodings) { + list = NULL; + size = 0; + php_mb_parse_encoding_list(_from_encodings, strlen(_from_encodings), &list, &size, 0 TSRMLS_CC); + if (size == 1) { + from_encoding = *list; + string.no_encoding = from_encoding->no_encoding; + } else if (size > 1) { + /* auto detect */ + from_encoding = mbfl_identify_encoding2(&string, list, size, MBSTRG(strict_detection)); + if (from_encoding) { + string.no_encoding = from_encoding->no_encoding; + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to detect character encoding"); + from_encoding = &mbfl_encoding_pass; + to_encoding = from_encoding; + string.no_encoding = from_encoding->no_encoding; + } + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Illegal character encoding specified"); + } + if (list != NULL) { + efree((void *)list); + } + } + + /* initialize converter */ + convd = mbfl_buffer_converter_new2(from_encoding, to_encoding, string.len); + if (convd == NULL) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create character encoding converter"); + return NULL; + } + mbfl_buffer_converter_illegal_mode(convd, MBSTRG(current_filter_illegal_mode)); + mbfl_buffer_converter_illegal_substchar(convd, MBSTRG(current_filter_illegal_substchar)); + + /* do it */ + ret = mbfl_buffer_converter_feed_result(convd, &string, &result); + if (ret) { + if (output_len) { + *output_len = ret->len; + } + output = (char *)ret->val; + } + + MBSTRG(illegalchars) += mbfl_buffer_illegalchars(convd); + mbfl_buffer_converter_delete(convd); + return output; +} +/* }}} */ + +/* {{{ proto string mb_convert_encoding(string str, string to-encoding [, mixed from-encoding]) + Returns converted string in desired encoding */ +PHP_FUNCTION(mb_convert_encoding) +{ + char *arg_str, *arg_new; + int str_len, new_len; + zval *arg_old; + int i; + size_t size, l, n; + char *_from_encodings = NULL, *ret, *s_free = NULL; + + zval **hash_entry; + HashTable *target_hash; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|z", &arg_str, &str_len, &arg_new, &new_len, &arg_old) == FAILURE) { + return; + } + + if (ZEND_NUM_ARGS() == 3) { + switch (Z_TYPE_P(arg_old)) { + case IS_ARRAY: + target_hash = Z_ARRVAL_P(arg_old); + zend_hash_internal_pointer_reset(target_hash); + i = zend_hash_num_elements(target_hash); + _from_encodings = NULL; + + while (i > 0) { + if (zend_hash_get_current_data(target_hash, (void **) &hash_entry) == FAILURE) { + break; + } + + convert_to_string_ex(hash_entry); + + if ( _from_encodings) { + l = strlen(_from_encodings); + n = strlen(Z_STRVAL_PP(hash_entry)); + _from_encodings = erealloc(_from_encodings, l+n+2); + strcpy(_from_encodings+l, ","); + strcpy(_from_encodings+l+1, Z_STRVAL_PP(hash_entry)); + } else { + _from_encodings = estrdup(Z_STRVAL_PP(hash_entry)); + } + + zend_hash_move_forward(target_hash); + i--; + } + + if (_from_encodings != NULL && !strlen(_from_encodings)) { + efree(_from_encodings); + _from_encodings = NULL; + } + s_free = _from_encodings; + break; + default: + convert_to_string(arg_old); + _from_encodings = Z_STRVAL_P(arg_old); + break; + } + } + + /* new encoding */ + ret = php_mb_convert_encoding(arg_str, str_len, arg_new, _from_encodings, &size TSRMLS_CC); + if (ret != NULL) { + RETVAL_STRINGL(ret, size, 0); /* the string is already strdup()'ed */ + } else { + RETVAL_FALSE; + } + + if ( s_free) { + efree(s_free); + } +} +/* }}} */ + +/* {{{ proto string mb_convert_case(string sourcestring, int mode [, string encoding]) + Returns a case-folded version of sourcestring */ +PHP_FUNCTION(mb_convert_case) +{ + const char *from_encoding = MBSTRG(current_internal_encoding)->mime_name; + char *str; + int str_len, from_encoding_len; + long case_mode = 0; + char *newstr; + size_t ret_len; + + RETVAL_FALSE; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|s!", &str, &str_len, + &case_mode, &from_encoding, &from_encoding_len) == FAILURE) + RETURN_FALSE; + + newstr = php_unicode_convert_case(case_mode, str, (size_t) str_len, &ret_len, from_encoding TSRMLS_CC); + + if (newstr) { + RETVAL_STRINGL(newstr, ret_len, 0); + } +} +/* }}} */ + +/* {{{ proto string mb_strtoupper(string sourcestring [, string encoding]) + * Returns a uppercased version of sourcestring + */ +PHP_FUNCTION(mb_strtoupper) +{ + const char *from_encoding = MBSTRG(current_internal_encoding)->mime_name; + char *str; + int str_len, from_encoding_len; + char *newstr; + size_t ret_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!", &str, &str_len, + &from_encoding, &from_encoding_len) == FAILURE) { + return; + } + newstr = php_unicode_convert_case(PHP_UNICODE_CASE_UPPER, str, (size_t) str_len, &ret_len, from_encoding TSRMLS_CC); + + if (newstr) { + RETURN_STRINGL(newstr, ret_len, 0); + } + RETURN_FALSE; +} +/* }}} */ + +/* {{{ proto string mb_strtolower(string sourcestring [, string encoding]) + * Returns a lowercased version of sourcestring + */ +PHP_FUNCTION(mb_strtolower) +{ + const char *from_encoding = MBSTRG(current_internal_encoding)->mime_name; + char *str; + int str_len, from_encoding_len; + char *newstr; + size_t ret_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!", &str, &str_len, + &from_encoding, &from_encoding_len) == FAILURE) { + return; + } + newstr = php_unicode_convert_case(PHP_UNICODE_CASE_LOWER, str, (size_t) str_len, &ret_len, from_encoding TSRMLS_CC); + + if (newstr) { + RETURN_STRINGL(newstr, ret_len, 0); + } + RETURN_FALSE; +} +/* }}} */ + +/* {{{ proto string mb_detect_encoding(string str [, mixed encoding_list [, bool strict]]) + Encodings of the given string is returned (as a string) */ +PHP_FUNCTION(mb_detect_encoding) +{ + char *str; + int str_len; + zend_bool strict=0; + zval *encoding_list; + + mbfl_string string; + const mbfl_encoding *ret; + const mbfl_encoding **elist, **list; + size_t size; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|zb", &str, &str_len, &encoding_list, &strict) == FAILURE) { + return; + } + + /* make encoding list */ + list = NULL; + size = 0; + if (ZEND_NUM_ARGS() >= 2 && !ZVAL_IS_NULL(encoding_list)) { + switch (Z_TYPE_P(encoding_list)) { + case IS_ARRAY: + if (FAILURE == php_mb_parse_encoding_array(encoding_list, &list, &size, 0 TSRMLS_CC)) { + if (list) { + efree(list); + list = NULL; + size = 0; + } + } + break; + default: + convert_to_string(encoding_list); + if (FAILURE == php_mb_parse_encoding_list(Z_STRVAL_P(encoding_list), Z_STRLEN_P(encoding_list), &list, &size, 0 TSRMLS_CC)) { + if (list) { + efree(list); + list = NULL; + size = 0; + } + } + break; + } + if (size <= 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Illegal argument"); + } + } + + if (ZEND_NUM_ARGS() < 3) { + strict = (zend_bool)MBSTRG(strict_detection); + } + + if (size > 0 && list != NULL) { + elist = list; + } else { + elist = MBSTRG(current_detect_order_list); + size = MBSTRG(current_detect_order_list_size); + } + + mbfl_string_init(&string); + string.no_language = MBSTRG(language); + string.val = (unsigned char *)str; + string.len = str_len; + ret = mbfl_identify_encoding2(&string, elist, size, strict); + + if (list != NULL) { + efree((void *)list); + } + + if (ret == NULL) { + RETURN_FALSE; + } + + RETVAL_STRING((char *)ret->name, 1); +} +/* }}} */ + +/* {{{ proto mixed mb_list_encodings() + Returns an array of all supported entity encodings */ +PHP_FUNCTION(mb_list_encodings) +{ + const mbfl_encoding **encodings; + const mbfl_encoding *encoding; + int i; + + array_init(return_value); + i = 0; + encodings = mbfl_get_supported_encodings(); + while ((encoding = encodings[i++]) != NULL) { + add_next_index_string(return_value, (char *) encoding->name, 1); + } +} +/* }}} */ + +/* {{{ proto array mb_encoding_aliases(string encoding) + Returns an array of the aliases of a given encoding name */ +PHP_FUNCTION(mb_encoding_aliases) +{ + const mbfl_encoding *encoding; + char *name = NULL; + int name_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) { + RETURN_FALSE; + } + + encoding = mbfl_name2encoding(name); + if (!encoding) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", name); + RETURN_FALSE; + } + + array_init(return_value); + if (encoding->aliases != NULL) { + const char **alias; + for (alias = *encoding->aliases; *alias; ++alias) { + add_next_index_string(return_value, (char *)*alias, 1); + } + } +} +/* }}} */ + +/* {{{ proto string mb_encode_mimeheader(string str [, string charset [, string transfer-encoding [, string linefeed [, int indent]]]]) + Converts the string to MIME "encoded-word" in the format of =?charset?(B|Q)?encoded_string?= */ +PHP_FUNCTION(mb_encode_mimeheader) +{ + enum mbfl_no_encoding charset, transenc; + mbfl_string string, result, *ret; + char *charset_name = NULL; + int charset_name_len; + char *trans_enc_name = NULL; + int trans_enc_name_len; + char *linefeed = "\r\n"; + int linefeed_len; + long indent = 0; + + mbfl_string_init(&string); + string.no_language = MBSTRG(language); + string.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|sssl", (char **)&string.val, &string.len, &charset_name, &charset_name_len, &trans_enc_name, &trans_enc_name_len, &linefeed, &linefeed_len, &indent) == FAILURE) { + return; + } + + charset = mbfl_no_encoding_pass; + transenc = mbfl_no_encoding_base64; + + if (charset_name != NULL) { + charset = mbfl_name2no_encoding(charset_name); + if (charset == mbfl_no_encoding_invalid) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", charset_name); + RETURN_FALSE; + } + } else { + const mbfl_language *lang = mbfl_no2language(MBSTRG(language)); + if (lang != NULL) { + charset = lang->mail_charset; + transenc = lang->mail_header_encoding; + } + } + + if (trans_enc_name != NULL) { + if (*trans_enc_name == 'B' || *trans_enc_name == 'b') { + transenc = mbfl_no_encoding_base64; + } else if (*trans_enc_name == 'Q' || *trans_enc_name == 'q') { + transenc = mbfl_no_encoding_qprint; + } + } + + mbfl_string_init(&result); + ret = mbfl_mime_header_encode(&string, &result, charset, transenc, linefeed, indent); + if (ret != NULL) { + RETVAL_STRINGL((char *)ret->val, ret->len, 0); /* the string is already strdup()'ed */ + } else { + RETVAL_FALSE; + } +} +/* }}} */ + +/* {{{ proto string mb_decode_mimeheader(string string) + Decodes the MIME "encoded-word" in the string */ +PHP_FUNCTION(mb_decode_mimeheader) +{ + mbfl_string string, result, *ret; + + mbfl_string_init(&string); + string.no_language = MBSTRG(language); + string.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", (char **)&string.val, &string.len) == FAILURE) { + return; + } + + mbfl_string_init(&result); + ret = mbfl_mime_header_decode(&string, &result, MBSTRG(current_internal_encoding)->no_encoding); + if (ret != NULL) { + RETVAL_STRINGL((char *)ret->val, ret->len, 0); /* the string is already strdup()'ed */ + } else { + RETVAL_FALSE; + } +} +/* }}} */ + +/* {{{ proto string mb_convert_kana(string str [, string option] [, string encoding]) + Conversion between full-width character and half-width character (Japanese) */ +PHP_FUNCTION(mb_convert_kana) +{ + int opt, i; + mbfl_string string, result, *ret; + char *optstr = NULL; + int optstr_len; + char *encname = NULL; + int encname_len; + + mbfl_string_init(&string); + string.no_language = MBSTRG(language); + string.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ss", (char **)&string.val, &string.len, &optstr, &optstr_len, &encname, &encname_len) == FAILURE) { + return; + } + + /* option */ + if (optstr != NULL) { + char *p = optstr; + int n = optstr_len; + i = 0; + opt = 0; + while (i < n) { + i++; + switch (*p++) { + case 'A': + opt |= 0x1; + break; + case 'a': + opt |= 0x10; + break; + case 'R': + opt |= 0x2; + break; + case 'r': + opt |= 0x20; + break; + case 'N': + opt |= 0x4; + break; + case 'n': + opt |= 0x40; + break; + case 'S': + opt |= 0x8; + break; + case 's': + opt |= 0x80; + break; + case 'K': + opt |= 0x100; + break; + case 'k': + opt |= 0x1000; + break; + case 'H': + opt |= 0x200; + break; + case 'h': + opt |= 0x2000; + break; + case 'V': + opt |= 0x800; + break; + case 'C': + opt |= 0x10000; + break; + case 'c': + opt |= 0x20000; + break; + case 'M': + opt |= 0x100000; + break; + case 'm': + opt |= 0x200000; + break; + } + } + } else { + opt = 0x900; + } + + /* encoding */ + if (encname != NULL) { + string.no_encoding = mbfl_name2no_encoding(encname); + if (string.no_encoding == mbfl_no_encoding_invalid) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", encname); + RETURN_FALSE; + } + } + + ret = mbfl_ja_jp_hantozen(&string, &result, opt); + if (ret != NULL) { + RETVAL_STRINGL((char *)ret->val, ret->len, 0); /* the string is already strdup()'ed */ + } else { + RETVAL_FALSE; + } +} +/* }}} */ + +#define PHP_MBSTR_STACK_BLOCK_SIZE 32 + +/* {{{ proto string mb_convert_variables(string to-encoding, mixed from-encoding, mixed vars [, ...]) + Converts the string resource in variables to desired encoding */ +PHP_FUNCTION(mb_convert_variables) +{ + zval ***args, ***stack, **var, **hash_entry, **zfrom_enc; + HashTable *target_hash; + mbfl_string string, result, *ret; + const mbfl_encoding *from_encoding, *to_encoding; + mbfl_encoding_detector *identd; + mbfl_buffer_converter *convd; + int n, to_enc_len, argc, stack_level, stack_max; + size_t elistsz; + const mbfl_encoding **elist; + char *to_enc; + void *ptmp; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sZ+", &to_enc, &to_enc_len, &zfrom_enc, &args, &argc) == FAILURE) { + return; + } + + /* new encoding */ + to_encoding = mbfl_name2encoding(to_enc); + if (!to_encoding) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", to_enc); + efree(args); + RETURN_FALSE; + } + + /* initialize string */ + mbfl_string_init(&string); + mbfl_string_init(&result); + from_encoding = MBSTRG(current_internal_encoding); + string.no_encoding = from_encoding->no_encoding; + string.no_language = MBSTRG(language); + + /* pre-conversion encoding */ + elist = NULL; + elistsz = 0; + switch (Z_TYPE_PP(zfrom_enc)) { + case IS_ARRAY: + php_mb_parse_encoding_array(*zfrom_enc, &elist, &elistsz, 0 TSRMLS_CC); + break; + default: + convert_to_string_ex(zfrom_enc); + php_mb_parse_encoding_list(Z_STRVAL_PP(zfrom_enc), Z_STRLEN_PP(zfrom_enc), &elist, &elistsz, 0 TSRMLS_CC); + break; + } + if (elistsz <= 0) { + from_encoding = &mbfl_encoding_pass; + } else if (elistsz == 1) { + from_encoding = *elist; + } else { + /* auto detect */ + from_encoding = NULL; + stack_max = PHP_MBSTR_STACK_BLOCK_SIZE; + stack = (zval ***)safe_emalloc(stack_max, sizeof(zval **), 0); + stack_level = 0; + identd = mbfl_encoding_detector_new2(elist, elistsz, MBSTRG(strict_detection)); + if (identd != NULL) { + n = 0; + while (n < argc || stack_level > 0) { + if (stack_level <= 0) { + var = args[n++]; + if (Z_TYPE_PP(var) == IS_ARRAY || Z_TYPE_PP(var) == IS_OBJECT) { + target_hash = HASH_OF(*var); + if (target_hash != NULL) { + zend_hash_internal_pointer_reset(target_hash); + } + } + } else { + stack_level--; + var = stack[stack_level]; + } + if (Z_TYPE_PP(var) == IS_ARRAY || Z_TYPE_PP(var) == IS_OBJECT) { + target_hash = HASH_OF(*var); + if (target_hash != NULL) { + while (zend_hash_get_current_data(target_hash, (void **) &hash_entry) != FAILURE) { + zend_hash_move_forward(target_hash); + if (Z_TYPE_PP(hash_entry) == IS_ARRAY || Z_TYPE_PP(hash_entry) == IS_OBJECT) { + if (stack_level >= stack_max) { + stack_max += PHP_MBSTR_STACK_BLOCK_SIZE; + ptmp = erealloc(stack, sizeof(zval **)*stack_max); + stack = (zval ***)ptmp; + } + stack[stack_level] = var; + stack_level++; + var = hash_entry; + target_hash = HASH_OF(*var); + if (target_hash != NULL) { + zend_hash_internal_pointer_reset(target_hash); + continue; + } + } else if (Z_TYPE_PP(hash_entry) == IS_STRING) { + string.val = (unsigned char *)Z_STRVAL_PP(hash_entry); + string.len = Z_STRLEN_PP(hash_entry); + if (mbfl_encoding_detector_feed(identd, &string)) { + goto detect_end; /* complete detecting */ + } + } + } + } + } else if (Z_TYPE_PP(var) == IS_STRING) { + string.val = (unsigned char *)Z_STRVAL_PP(var); + string.len = Z_STRLEN_PP(var); + if (mbfl_encoding_detector_feed(identd, &string)) { + goto detect_end; /* complete detecting */ + } + } + } +detect_end: + from_encoding = mbfl_encoding_detector_judge2(identd); + mbfl_encoding_detector_delete(identd); + } + efree(stack); + + if (!from_encoding) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to detect encoding"); + from_encoding = &mbfl_encoding_pass; + } + } + if (elist != NULL) { + efree((void *)elist); + } + /* create converter */ + convd = NULL; + if (from_encoding != &mbfl_encoding_pass) { + convd = mbfl_buffer_converter_new2(from_encoding, to_encoding, 0); + if (convd == NULL) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create converter"); + RETURN_FALSE; + } + mbfl_buffer_converter_illegal_mode(convd, MBSTRG(current_filter_illegal_mode)); + mbfl_buffer_converter_illegal_substchar(convd, MBSTRG(current_filter_illegal_substchar)); + } + + /* convert */ + if (convd != NULL) { + stack_max = PHP_MBSTR_STACK_BLOCK_SIZE; + stack = (zval ***)safe_emalloc(stack_max, sizeof(zval **), 0); + stack_level = 0; + n = 0; + while (n < argc || stack_level > 0) { + if (stack_level <= 0) { + var = args[n++]; + if (Z_TYPE_PP(var) == IS_ARRAY || Z_TYPE_PP(var) == IS_OBJECT) { + target_hash = HASH_OF(*var); + if (target_hash != NULL) { + zend_hash_internal_pointer_reset(target_hash); + } + } + } else { + stack_level--; + var = stack[stack_level]; + } + if (Z_TYPE_PP(var) == IS_ARRAY || Z_TYPE_PP(var) == IS_OBJECT) { + target_hash = HASH_OF(*var); + if (target_hash != NULL) { + while (zend_hash_get_current_data(target_hash, (void **) &hash_entry) != FAILURE) { + zend_hash_move_forward(target_hash); + if (Z_TYPE_PP(hash_entry) == IS_ARRAY || Z_TYPE_PP(hash_entry) == IS_OBJECT) { + if (stack_level >= stack_max) { + stack_max += PHP_MBSTR_STACK_BLOCK_SIZE; + ptmp = erealloc(stack, sizeof(zval **)*stack_max); + stack = (zval ***)ptmp; + } + stack[stack_level] = var; + stack_level++; + var = hash_entry; + SEPARATE_ZVAL(hash_entry); + target_hash = HASH_OF(*var); + if (target_hash != NULL) { + zend_hash_internal_pointer_reset(target_hash); + continue; + } + } else if (Z_TYPE_PP(hash_entry) == IS_STRING) { + string.val = (unsigned char *)Z_STRVAL_PP(hash_entry); + string.len = Z_STRLEN_PP(hash_entry); + ret = mbfl_buffer_converter_feed_result(convd, &string, &result); + if (ret != NULL) { + if (Z_REFCOUNT_PP(hash_entry) > 1) { + Z_DELREF_PP(hash_entry); + MAKE_STD_ZVAL(*hash_entry); + } else { + zval_dtor(*hash_entry); + } + ZVAL_STRINGL(*hash_entry, (char *)ret->val, ret->len, 0); + } + } + } + } + } else if (Z_TYPE_PP(var) == IS_STRING) { + string.val = (unsigned char *)Z_STRVAL_PP(var); + string.len = Z_STRLEN_PP(var); + ret = mbfl_buffer_converter_feed_result(convd, &string, &result); + if (ret != NULL) { + zval_dtor(*var); + ZVAL_STRINGL(*var, (char *)ret->val, ret->len, 0); + } + } + } + efree(stack); + + MBSTRG(illegalchars) += mbfl_buffer_illegalchars(convd); + mbfl_buffer_converter_delete(convd); + } + + efree(args); + + if (from_encoding) { + RETURN_STRING(from_encoding->name, 1); + } else { + RETURN_FALSE; + } +} +/* }}} */ + +/* {{{ HTML numeric entity */ +/* {{{ static void php_mb_numericentity_exec() */ +static void +php_mb_numericentity_exec(INTERNAL_FUNCTION_PARAMETERS, int type) +{ + char *str, *encoding; + int str_len, encoding_len; + zval *zconvmap, **hash_entry; + HashTable *target_hash; + size_t argc = ZEND_NUM_ARGS(); + int i, *convmap, *mapelm, mapsize=0; + zend_bool is_hex = 0; + mbfl_string string, result, *ret; + enum mbfl_no_encoding no_encoding; + + if (zend_parse_parameters(argc TSRMLS_CC, "sz|sb", &str, &str_len, &zconvmap, &encoding, &encoding_len, &is_hex) == FAILURE) { + return; + } + + mbfl_string_init(&string); + string.no_language = MBSTRG(language); + string.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; + string.val = (unsigned char *)str; + string.len = str_len; + + /* encoding */ + if ((argc == 3 || argc == 4) && encoding_len > 0) { + no_encoding = mbfl_name2no_encoding(encoding); + if (no_encoding == mbfl_no_encoding_invalid) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", encoding); + RETURN_FALSE; + } else { + string.no_encoding = no_encoding; + } + } + + if (argc == 4) { + if (type == 0 && is_hex) { + type = 2; /* output in hex format */ + } + } + + /* conversion map */ + convmap = NULL; + if (Z_TYPE_P(zconvmap) == IS_ARRAY) { + target_hash = Z_ARRVAL_P(zconvmap); + zend_hash_internal_pointer_reset(target_hash); + i = zend_hash_num_elements(target_hash); + if (i > 0) { + convmap = (int *)safe_emalloc(i, sizeof(int), 0); + mapelm = convmap; + mapsize = 0; + while (i > 0) { + if (zend_hash_get_current_data(target_hash, (void **) &hash_entry) == FAILURE) { + break; + } + convert_to_long_ex(hash_entry); + *mapelm++ = Z_LVAL_PP(hash_entry); + mapsize++; + i--; + zend_hash_move_forward(target_hash); + } + } + } + if (convmap == NULL) { + RETURN_FALSE; + } + mapsize /= 4; + + ret = mbfl_html_numeric_entity(&string, &result, convmap, mapsize, type); + if (ret != NULL) { + RETVAL_STRINGL((char *)ret->val, ret->len, 0); + } else { + RETVAL_FALSE; + } + efree((void *)convmap); +} +/* }}} */ + +/* {{{ proto string mb_encode_numericentity(string string, array convmap [, string encoding [, bool is_hex]]) + Converts specified characters to HTML numeric entities */ +PHP_FUNCTION(mb_encode_numericentity) +{ + php_mb_numericentity_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); +} +/* }}} */ + +/* {{{ proto string mb_decode_numericentity(string string, array convmap [, string encoding]) + Converts HTML numeric entities to character code */ +PHP_FUNCTION(mb_decode_numericentity) +{ + php_mb_numericentity_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); +} +/* }}} */ +/* }}} */ + +/* {{{ proto int mb_send_mail(string to, string subject, string message [, string additional_headers [, string additional_parameters]]) + * Sends an email message with MIME scheme + */ + +#define SKIP_LONG_HEADER_SEP_MBSTRING(str, pos) \ + if (str[pos] == '\r' && str[pos + 1] == '\n' && (str[pos + 2] == ' ' || str[pos + 2] == '\t')) { \ + pos += 2; \ + while (str[pos + 1] == ' ' || str[pos + 1] == '\t') { \ + pos++; \ + } \ + continue; \ + } + +#define MAIL_ASCIIZ_CHECK_MBSTRING(str, len) \ + pp = str; \ + ee = pp + len; \ + while ((pp = memchr(pp, '\0', (ee - pp)))) { \ + *pp = ' '; \ + } \ + +#define APPEND_ONE_CHAR(ch) do { \ + if (token.a > 0) { \ + smart_str_appendc(&token, ch); \ + } else {\ + token.len++; \ + } \ +} while (0) + +#define SEPARATE_SMART_STR(str) do {\ + if ((str)->a == 0) { \ + char *tmp_ptr; \ + (str)->a = 1; \ + while ((str)->a < (str)->len) { \ + (str)->a <<= 1; \ + } \ + tmp_ptr = emalloc((str)->a + 1); \ + memcpy(tmp_ptr, (str)->c, (str)->len); \ + (str)->c = tmp_ptr; \ + } \ +} while (0) + +static void my_smart_str_dtor(smart_str *s) +{ + if (s->a > 0) { + smart_str_free(s); + } +} + +static int _php_mbstr_parse_mail_headers(HashTable *ht, const char *str, size_t str_len) +{ + const char *ps; + size_t icnt; + int state = 0; + int crlf_state = -1; + + smart_str token = { 0, 0, 0 }; + smart_str fld_name = { 0, 0, 0 }, fld_val = { 0, 0, 0 }; + + ps = str; + icnt = str_len; + + /* + * C o n t e n t - T y p e : t e x t / h t m l \r\n + * ^ ^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^^^^^^^^^ ^^^^ + * state 0 1 2 3 + * + * C o n t e n t - T y p e : t e x t / h t m l \r\n + * ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^ + * crlf_state -1 0 1 -1 + * + */ + + while (icnt > 0) { + switch (*ps) { + case ':': + if (crlf_state == 1) { + APPEND_ONE_CHAR('\r'); + } + + if (state == 0 || state == 1) { + fld_name = token; + + state = 2; + } else { + APPEND_ONE_CHAR(*ps); + } + + crlf_state = 0; + break; + + case '\n': + if (crlf_state == -1) { + goto out; + } + crlf_state = -1; + break; + + case '\r': + if (crlf_state == 1) { + APPEND_ONE_CHAR('\r'); + } else { + crlf_state = 1; + } + break; + + case ' ': case '\t': + if (crlf_state == -1) { + if (state == 3) { + /* continuing from the previous line */ + SEPARATE_SMART_STR(&token); + state = 4; + } else { + /* simply skipping this new line */ + state = 5; + } + } else { + if (crlf_state == 1) { + APPEND_ONE_CHAR('\r'); + } + if (state == 1 || state == 3) { + APPEND_ONE_CHAR(*ps); + } + } + crlf_state = 0; + break; + + default: + switch (state) { + case 0: + token.c = (char *)ps; + token.len = 0; + token.a = 0; + state = 1; + break; + + case 2: + if (crlf_state != -1) { + token.c = (char *)ps; + token.len = 0; + token.a = 0; + + state = 3; + break; + } + /* break is missing intentionally */ + + case 3: + if (crlf_state == -1) { + fld_val = token; + + if (fld_name.c != NULL && fld_val.c != NULL) { + char *dummy; + + /* FIXME: some locale free implementation is + * really required here,,, */ + SEPARATE_SMART_STR(&fld_name); + php_strtoupper(fld_name.c, fld_name.len); + + zend_hash_update(ht, (char *)fld_name.c, fld_name.len, &fld_val, sizeof(smart_str), (void **)&dummy); + + my_smart_str_dtor(&fld_name); + } + + memset(&fld_name, 0, sizeof(smart_str)); + memset(&fld_val, 0, sizeof(smart_str)); + + token.c = (char *)ps; + token.len = 0; + token.a = 0; + + state = 1; + } + break; + + case 4: + APPEND_ONE_CHAR(' '); + state = 3; + break; + } + + if (crlf_state == 1) { + APPEND_ONE_CHAR('\r'); + } + + APPEND_ONE_CHAR(*ps); + + crlf_state = 0; + break; + } + ps++, icnt--; + } +out: + if (state == 2) { + token.c = ""; + token.len = 0; + token.a = 0; + + state = 3; + } + if (state == 3) { + fld_val = token; + + if (fld_name.c != NULL && fld_val.c != NULL) { + void *dummy; + + /* FIXME: some locale free implementation is + * really required here,,, */ + SEPARATE_SMART_STR(&fld_name); + php_strtoupper(fld_name.c, fld_name.len); + + zend_hash_update(ht, (char *)fld_name.c, fld_name.len, &fld_val, sizeof(smart_str), (void **)&dummy); + + my_smart_str_dtor(&fld_name); + } + } + return state; +} + +PHP_FUNCTION(mb_send_mail) +{ + int n; + char *to = NULL; + int to_len; + char *message = NULL; + int message_len; + char *headers = NULL; + int headers_len; + char *subject = NULL; + int subject_len; + char *extra_cmd = NULL; + int extra_cmd_len; + int i; + char *to_r = NULL; + char *force_extra_parameters = INI_STR("mail.force_extra_parameters"); + struct { + int cnt_type:1; + int cnt_trans_enc:1; + } suppressed_hdrs = { 0, 0 }; + + char *message_buf = NULL, *subject_buf = NULL, *p; + mbfl_string orig_str, conv_str; + mbfl_string *pstr; /* pointer to mbfl string for return value */ + enum mbfl_no_encoding + tran_cs, /* transfar text charset */ + head_enc, /* header transfar encoding */ + body_enc; /* body transfar encoding */ + mbfl_memory_device device; /* automatic allocateable buffer for additional header */ + const mbfl_language *lang; + int err = 0; + HashTable ht_headers; + smart_str *s; + extern void mbfl_memory_device_unput(mbfl_memory_device *device); + char *pp, *ee; + + /* initialize */ + mbfl_memory_device_init(&device, 0, 0); + mbfl_string_init(&orig_str); + mbfl_string_init(&conv_str); + + /* character-set, transfer-encoding */ + tran_cs = mbfl_no_encoding_utf8; + head_enc = mbfl_no_encoding_base64; + body_enc = mbfl_no_encoding_base64; + lang = mbfl_no2language(MBSTRG(language)); + if (lang != NULL) { + tran_cs = lang->mail_charset; + head_enc = lang->mail_header_encoding; + body_enc = lang->mail_body_encoding; + } + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|ss", &to, &to_len, &subject, &subject_len, &message, &message_len, &headers, &headers_len, &extra_cmd, &extra_cmd_len) == FAILURE) { + return; + } + + /* ASCIIZ check */ + MAIL_ASCIIZ_CHECK_MBSTRING(to, to_len); + MAIL_ASCIIZ_CHECK_MBSTRING(subject, subject_len); + MAIL_ASCIIZ_CHECK_MBSTRING(message, message_len); + if (headers) { + MAIL_ASCIIZ_CHECK_MBSTRING(headers, headers_len); + } + if (extra_cmd) { + MAIL_ASCIIZ_CHECK_MBSTRING(extra_cmd, extra_cmd_len); + } + + zend_hash_init(&ht_headers, 0, NULL, (dtor_func_t) my_smart_str_dtor, 0); + + if (headers != NULL) { + _php_mbstr_parse_mail_headers(&ht_headers, headers, headers_len); + } + + if (zend_hash_find(&ht_headers, "CONTENT-TYPE", sizeof("CONTENT-TYPE") - 1, (void **)&s) == SUCCESS) { + char *tmp; + char *param_name; + char *charset = NULL; + + SEPARATE_SMART_STR(s); + smart_str_0(s); + + p = strchr(s->c, ';'); + + if (p != NULL) { + /* skipping the padded spaces */ + do { + ++p; + } while (*p == ' ' || *p == '\t'); + + if (*p != '\0') { + if ((param_name = php_strtok_r(p, "= ", &tmp)) != NULL) { + if (strcasecmp(param_name, "charset") == 0) { + enum mbfl_no_encoding _tran_cs = tran_cs; + + charset = php_strtok_r(NULL, "= \"", &tmp); + if (charset != NULL) { + _tran_cs = mbfl_name2no_encoding(charset); + } + + if (_tran_cs == mbfl_no_encoding_invalid) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported charset \"%s\" - will be regarded as ascii", charset); + _tran_cs = mbfl_no_encoding_ascii; + } + tran_cs = _tran_cs; + } + } + } + } + suppressed_hdrs.cnt_type = 1; + } + + if (zend_hash_find(&ht_headers, "CONTENT-TRANSFER-ENCODING", sizeof("CONTENT-TRANSFER-ENCODING") - 1, (void **)&s) == SUCCESS) { + enum mbfl_no_encoding _body_enc; + SEPARATE_SMART_STR(s); + smart_str_0(s); + + _body_enc = mbfl_name2no_encoding(s->c); + switch (_body_enc) { + case mbfl_no_encoding_base64: + case mbfl_no_encoding_7bit: + case mbfl_no_encoding_8bit: + body_enc = _body_enc; + break; + + default: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported transfer encoding \"%s\" - will be regarded as 8bit", s->c); + body_enc = mbfl_no_encoding_8bit; + break; + } + suppressed_hdrs.cnt_trans_enc = 1; + } + + /* To: */ + if (to != NULL) { + if (to_len > 0) { + to_r = estrndup(to, to_len); + for (; to_len; to_len--) { + if (!isspace((unsigned char) to_r[to_len - 1])) { + break; + } + to_r[to_len - 1] = '\0'; + } + for (i = 0; to_r[i]; i++) { + if (iscntrl((unsigned char) to_r[i])) { + /* According to RFC 822, section 3.1.1 long headers may be separated into + * parts using CRLF followed at least one linear-white-space character ('\t' or ' '). + * To prevent these separators from being replaced with a space, we use the + * SKIP_LONG_HEADER_SEP_MBSTRING to skip over them. + */ + SKIP_LONG_HEADER_SEP_MBSTRING(to_r, i); + to_r[i] = ' '; + } + } + } else { + to_r = to; + } + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Missing To: field"); + err = 1; + } + + /* Subject: */ + if (subject != NULL && subject_len >= 0) { + orig_str.no_language = MBSTRG(language); + orig_str.val = (unsigned char *)subject; + orig_str.len = subject_len; + orig_str.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; + if (orig_str.no_encoding == mbfl_no_encoding_invalid || orig_str.no_encoding == mbfl_no_encoding_pass) { + const mbfl_encoding *encoding = mbfl_identify_encoding2(&orig_str, MBSTRG(current_detect_order_list), MBSTRG(current_detect_order_list_size), MBSTRG(strict_detection)); + orig_str.no_encoding = encoding ? encoding->no_encoding: mbfl_no_encoding_invalid; + } + pstr = mbfl_mime_header_encode(&orig_str, &conv_str, tran_cs, head_enc, "\n", sizeof("Subject: [PHP-jp nnnnnnnn]")); + if (pstr != NULL) { + subject_buf = subject = (char *)pstr->val; + } + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Missing Subject: field"); + err = 1; + } + + /* message body */ + if (message != NULL) { + orig_str.no_language = MBSTRG(language); + orig_str.val = (unsigned char *)message; + orig_str.len = (unsigned int)message_len; + orig_str.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; + + if (orig_str.no_encoding == mbfl_no_encoding_invalid || orig_str.no_encoding == mbfl_no_encoding_pass) { + const mbfl_encoding *encoding = mbfl_identify_encoding2(&orig_str, MBSTRG(current_detect_order_list), MBSTRG(current_detect_order_list_size), MBSTRG(strict_detection)); + orig_str.no_encoding = encoding ? encoding->no_encoding: mbfl_no_encoding_invalid; + } + + pstr = NULL; + { + mbfl_string tmpstr; + + if (mbfl_convert_encoding(&orig_str, &tmpstr, tran_cs) != NULL) { + tmpstr.no_encoding=mbfl_no_encoding_8bit; + pstr = mbfl_convert_encoding(&tmpstr, &conv_str, body_enc); + efree(tmpstr.val); + } + } + if (pstr != NULL) { + message_buf = message = (char *)pstr->val; + } + } else { + /* this is not really an error, so it is allowed. */ + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty message body"); + message = NULL; + } + + /* other headers */ +#define PHP_MBSTR_MAIL_MIME_HEADER1 "MIME-Version: 1.0" +#define PHP_MBSTR_MAIL_MIME_HEADER2 "Content-Type: text/plain" +#define PHP_MBSTR_MAIL_MIME_HEADER3 "; charset=" +#define PHP_MBSTR_MAIL_MIME_HEADER4 "Content-Transfer-Encoding: " + if (headers != NULL) { + p = headers; + n = headers_len; + mbfl_memory_device_strncat(&device, p, n); + if (n > 0 && p[n - 1] != '\n') { + mbfl_memory_device_strncat(&device, "\n", 1); + } + } + + if (!zend_hash_exists(&ht_headers, "MIME-VERSION", sizeof("MIME-VERSION") - 1)) { + mbfl_memory_device_strncat(&device, PHP_MBSTR_MAIL_MIME_HEADER1, sizeof(PHP_MBSTR_MAIL_MIME_HEADER1) - 1); + mbfl_memory_device_strncat(&device, "\n", 1); + } + + if (!suppressed_hdrs.cnt_type) { + mbfl_memory_device_strncat(&device, PHP_MBSTR_MAIL_MIME_HEADER2, sizeof(PHP_MBSTR_MAIL_MIME_HEADER2) - 1); + + p = (char *)mbfl_no2preferred_mime_name(tran_cs); + if (p != NULL) { + mbfl_memory_device_strncat(&device, PHP_MBSTR_MAIL_MIME_HEADER3, sizeof(PHP_MBSTR_MAIL_MIME_HEADER3) - 1); + mbfl_memory_device_strcat(&device, p); + } + mbfl_memory_device_strncat(&device, "\n", 1); + } + if (!suppressed_hdrs.cnt_trans_enc) { + mbfl_memory_device_strncat(&device, PHP_MBSTR_MAIL_MIME_HEADER4, sizeof(PHP_MBSTR_MAIL_MIME_HEADER4) - 1); + p = (char *)mbfl_no2preferred_mime_name(body_enc); + if (p == NULL) { + p = "7bit"; + } + mbfl_memory_device_strcat(&device, p); + mbfl_memory_device_strncat(&device, "\n", 1); + } + + mbfl_memory_device_unput(&device); + mbfl_memory_device_output('\0', &device); + headers = (char *)device.buffer; + + if (force_extra_parameters) { + extra_cmd = php_escape_shell_cmd(force_extra_parameters); + } else if (extra_cmd) { + extra_cmd = php_escape_shell_cmd(extra_cmd); + } + + if (!err && php_mail(to_r, subject, message, headers, extra_cmd TSRMLS_CC)) { + RETVAL_TRUE; + } else { + RETVAL_FALSE; + } + + if (extra_cmd) { + efree(extra_cmd); + } + if (to_r != to) { + efree(to_r); + } + if (subject_buf) { + efree((void *)subject_buf); + } + if (message_buf) { + efree((void *)message_buf); + } + mbfl_memory_device_clear(&device); + zend_hash_destroy(&ht_headers); +} + +#undef SKIP_LONG_HEADER_SEP_MBSTRING +#undef MAIL_ASCIIZ_CHECK_MBSTRING +#undef APPEND_ONE_CHAR +#undef SEPARATE_SMART_STR +#undef PHP_MBSTR_MAIL_MIME_HEADER1 +#undef PHP_MBSTR_MAIL_MIME_HEADER2 +#undef PHP_MBSTR_MAIL_MIME_HEADER3 +#undef PHP_MBSTR_MAIL_MIME_HEADER4 +/* }}} */ + +/* {{{ proto mixed mb_get_info([string type]) + Returns the current settings of mbstring */ +PHP_FUNCTION(mb_get_info) +{ + char *typ = NULL; + int typ_len; + size_t n; + char *name; + const struct mb_overload_def *over_func; + zval *row1, *row2; + const mbfl_language *lang = mbfl_no2language(MBSTRG(language)); + const mbfl_encoding **entry; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &typ, &typ_len) == FAILURE) { + RETURN_FALSE; + } + + if (!typ || !strcasecmp("all", typ)) { + array_init(return_value); + if (MBSTRG(current_internal_encoding)) { + add_assoc_string(return_value, "internal_encoding", (char *)MBSTRG(current_internal_encoding)->name, 1); + } + if (MBSTRG(http_input_identify)) { + add_assoc_string(return_value, "http_input", (char *)MBSTRG(http_input_identify)->name, 1); + } + if (MBSTRG(current_http_output_encoding)) { + add_assoc_string(return_value, "http_output", (char *)MBSTRG(current_http_output_encoding)->name, 1); + } + if ((name = (char *)zend_ini_string("mbstring.http_output_conv_mimetypes", sizeof("mbstring.http_output_conv_mimetypes"), 0)) != NULL) { + add_assoc_string(return_value, "http_output_conv_mimetypes", name, 1); + } + add_assoc_long(return_value, "func_overload", MBSTRG(func_overload)); + if (MBSTRG(func_overload)){ + over_func = &(mb_ovld[0]); + MAKE_STD_ZVAL(row1); + array_init(row1); + while (over_func->type > 0) { + if ((MBSTRG(func_overload) & over_func->type) == over_func->type ) { + add_assoc_string(row1, over_func->orig_func, over_func->ovld_func, 1); + } + over_func++; + } + add_assoc_zval(return_value, "func_overload_list", row1); + } else { + add_assoc_string(return_value, "func_overload_list", "no overload", 1); + } + if (lang != NULL) { + if ((name = (char *)mbfl_no_encoding2name(lang->mail_charset)) != NULL) { + add_assoc_string(return_value, "mail_charset", name, 1); + } + if ((name = (char *)mbfl_no_encoding2name(lang->mail_header_encoding)) != NULL) { + add_assoc_string(return_value, "mail_header_encoding", name, 1); + } + if ((name = (char *)mbfl_no_encoding2name(lang->mail_body_encoding)) != NULL) { + add_assoc_string(return_value, "mail_body_encoding", name, 1); + } + } + add_assoc_long(return_value, "illegal_chars", MBSTRG(illegalchars)); + if (MBSTRG(encoding_translation)) { + add_assoc_string(return_value, "encoding_translation", "On", 1); + } else { + add_assoc_string(return_value, "encoding_translation", "Off", 1); + } + if ((name = (char *)mbfl_no_language2name(MBSTRG(language))) != NULL) { + add_assoc_string(return_value, "language", name, 1); + } + n = MBSTRG(current_detect_order_list_size); + entry = MBSTRG(current_detect_order_list); + if (n > 0) { + size_t i; + MAKE_STD_ZVAL(row2); + array_init(row2); + for (i = 0; i < n; i++) { + add_next_index_string(row2, (*entry)->name, 1); + entry++; + } + add_assoc_zval(return_value, "detect_order", row2); + } + if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE) { + add_assoc_string(return_value, "substitute_character", "none", 1); + } else if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_LONG) { + add_assoc_string(return_value, "substitute_character", "long", 1); + } else if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_ENTITY) { + add_assoc_string(return_value, "substitute_character", "entity", 1); + } else { + add_assoc_long(return_value, "substitute_character", MBSTRG(current_filter_illegal_substchar)); + } + if (MBSTRG(strict_detection)) { + add_assoc_string(return_value, "strict_detection", "On", 1); + } else { + add_assoc_string(return_value, "strict_detection", "Off", 1); + } + } else if (!strcasecmp("internal_encoding", typ)) { + if (MBSTRG(current_internal_encoding)) { + RETVAL_STRING((char *)MBSTRG(current_internal_encoding)->name, 1); + } + } else if (!strcasecmp("http_input", typ)) { + if (MBSTRG(http_input_identify)) { + RETVAL_STRING((char *)MBSTRG(http_input_identify)->name, 1); + } + } else if (!strcasecmp("http_output", typ)) { + if (MBSTRG(current_http_output_encoding)) { + RETVAL_STRING((char *)MBSTRG(current_http_output_encoding)->name, 1); + } + } else if (!strcasecmp("http_output_conv_mimetypes", typ)) { + if ((name = (char *)zend_ini_string("mbstring.http_output_conv_mimetypes", sizeof("mbstring.http_output_conv_mimetypes"), 0)) != NULL) { + RETVAL_STRING(name, 1); + } + } else if (!strcasecmp("func_overload", typ)) { + RETVAL_LONG(MBSTRG(func_overload)); + } else if (!strcasecmp("func_overload_list", typ)) { + if (MBSTRG(func_overload)){ + over_func = &(mb_ovld[0]); + array_init(return_value); + while (over_func->type > 0) { + if ((MBSTRG(func_overload) & over_func->type) == over_func->type ) { + add_assoc_string(return_value, over_func->orig_func, over_func->ovld_func, 1); + } + over_func++; + } + } else { + RETVAL_STRING("no overload", 1); + } + } else if (!strcasecmp("mail_charset", typ)) { + if (lang != NULL && (name = (char *)mbfl_no_encoding2name(lang->mail_charset)) != NULL) { + RETVAL_STRING(name, 1); + } + } else if (!strcasecmp("mail_header_encoding", typ)) { + if (lang != NULL && (name = (char *)mbfl_no_encoding2name(lang->mail_header_encoding)) != NULL) { + RETVAL_STRING(name, 1); + } + } else if (!strcasecmp("mail_body_encoding", typ)) { + if (lang != NULL && (name = (char *)mbfl_no_encoding2name(lang->mail_body_encoding)) != NULL) { + RETVAL_STRING(name, 1); + } + } else if (!strcasecmp("illegal_chars", typ)) { + RETVAL_LONG(MBSTRG(illegalchars)); + } else if (!strcasecmp("encoding_translation", typ)) { + if (MBSTRG(encoding_translation)) { + RETVAL_STRING("On", 1); + } else { + RETVAL_STRING("Off", 1); + } + } else if (!strcasecmp("language", typ)) { + if ((name = (char *)mbfl_no_language2name(MBSTRG(language))) != NULL) { + RETVAL_STRING(name, 1); + } + } else if (!strcasecmp("detect_order", typ)) { + n = MBSTRG(current_detect_order_list_size); + entry = MBSTRG(current_detect_order_list); + if (n > 0) { + size_t i; + array_init(return_value); + for (i = 0; i < n; i++) { + add_next_index_string(return_value, (*entry)->name, 1); + entry++; + } + } + } else if (!strcasecmp("substitute_character", typ)) { + if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE) { + RETVAL_STRING("none", 1); + } else if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_LONG) { + RETVAL_STRING("long", 1); + } else if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_ENTITY) { + RETVAL_STRING("entity", 1); + } else { + RETVAL_LONG(MBSTRG(current_filter_illegal_substchar)); + } + } else if (!strcasecmp("strict_detection", typ)) { + if (MBSTRG(strict_detection)) { + RETVAL_STRING("On", 1); + } else { + RETVAL_STRING("Off", 1); + } + } else { + RETURN_FALSE; + } +} +/* }}} */ + +/* {{{ proto bool mb_check_encoding([string var[, string encoding]]) + Check if the string is valid for the specified encoding */ +PHP_FUNCTION(mb_check_encoding) +{ + char *var = NULL; + int var_len; + char *enc = NULL; + int enc_len; + mbfl_buffer_converter *convd; + const mbfl_encoding *encoding = MBSTRG(current_internal_encoding); + mbfl_string string, result, *ret = NULL; + long illegalchars = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ss", &var, &var_len, &enc, &enc_len) == FAILURE) { + RETURN_FALSE; + } + + if (var == NULL) { + RETURN_BOOL(MBSTRG(illegalchars) == 0); + } + + if (enc != NULL) { + encoding = mbfl_name2encoding(enc); + if (!encoding || encoding == &mbfl_encoding_pass) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid encoding \"%s\"", enc); + RETURN_FALSE; + } + } + + convd = mbfl_buffer_converter_new2(encoding, encoding, 0); + if (convd == NULL) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create converter"); + RETURN_FALSE; + } + mbfl_buffer_converter_illegal_mode(convd, MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE); + mbfl_buffer_converter_illegal_substchar(convd, 0); + + /* initialize string */ + mbfl_string_init_set(&string, mbfl_no_language_neutral, encoding->no_encoding); + mbfl_string_init(&result); + + string.val = (unsigned char *)var; + string.len = var_len; + ret = mbfl_buffer_converter_feed_result(convd, &string, &result); + illegalchars = mbfl_buffer_illegalchars(convd); + mbfl_buffer_converter_delete(convd); + + RETVAL_FALSE; + if (ret != NULL) { + if (illegalchars == 0 && string.len == result.len && memcmp(string.val, result.val, string.len) == 0) { + RETVAL_TRUE; + } + mbfl_string_clear(&result); + } +} +/* }}} */ + + +/* {{{ php_mb_populate_current_detect_order_list */ +static void php_mb_populate_current_detect_order_list(TSRMLS_D) +{ + const mbfl_encoding **entry = 0; + size_t nentries; + + if (MBSTRG(current_detect_order_list)) { + return; + } + + if (MBSTRG(detect_order_list) && MBSTRG(detect_order_list_size)) { + nentries = MBSTRG(detect_order_list_size); + entry = (const mbfl_encoding **)safe_emalloc(nentries, sizeof(mbfl_encoding*), 0); + memcpy(entry, MBSTRG(detect_order_list), sizeof(mbfl_encoding*) * nentries); + } else { + const enum mbfl_no_encoding *src = MBSTRG(default_detect_order_list); + size_t i; + nentries = MBSTRG(default_detect_order_list_size); + entry = (const mbfl_encoding **)safe_emalloc(nentries, sizeof(mbfl_encoding*), 0); + for (i = 0; i < nentries; i++) { + entry[i] = mbfl_no2encoding(src[i]); + } + } + MBSTRG(current_detect_order_list) = entry; + MBSTRG(current_detect_order_list_size) = nentries; +} + +/* {{{ static int php_mb_encoding_translation() */ +static int php_mb_encoding_translation(TSRMLS_D) +{ + return MBSTRG(encoding_translation); +} +/* }}} */ + +/* {{{ MBSTRING_API size_t php_mb_mbchar_bytes_ex() */ +MBSTRING_API size_t php_mb_mbchar_bytes_ex(const char *s, const mbfl_encoding *enc) +{ + if (enc != NULL) { + if (enc->flag & MBFL_ENCTYPE_MBCS) { + if (enc->mblen_table != NULL) { + if (s != NULL) return enc->mblen_table[*(unsigned char *)s]; + } + } else if (enc->flag & (MBFL_ENCTYPE_WCS2BE | MBFL_ENCTYPE_WCS2LE)) { + return 2; + } else if (enc->flag & (MBFL_ENCTYPE_WCS4BE | MBFL_ENCTYPE_WCS4LE)) { + return 4; + } + } + return 1; +} +/* }}} */ + +/* {{{ MBSTRING_API size_t php_mb_mbchar_bytes() */ +MBSTRING_API size_t php_mb_mbchar_bytes(const char *s TSRMLS_DC) +{ + return php_mb_mbchar_bytes_ex(s, MBSTRG(internal_encoding)); +} +/* }}} */ + +/* {{{ MBSTRING_API char *php_mb_safe_strrchr_ex() */ +MBSTRING_API char *php_mb_safe_strrchr_ex(const char *s, unsigned int c, size_t nbytes, const mbfl_encoding *enc) +{ + register const char *p = s; + char *last=NULL; + + if (nbytes == (size_t)-1) { + size_t nb = 0; + + while (*p != '\0') { + if (nb == 0) { + if ((unsigned char)*p == (unsigned char)c) { + last = (char *)p; + } + nb = php_mb_mbchar_bytes_ex(p, enc); + if (nb == 0) { + return NULL; /* something is going wrong! */ + } + } + --nb; + ++p; + } + } else { + register size_t bcnt = nbytes; + register size_t nbytes_char; + while (bcnt > 0) { + if ((unsigned char)*p == (unsigned char)c) { + last = (char *)p; + } + nbytes_char = php_mb_mbchar_bytes_ex(p, enc); + if (bcnt < nbytes_char) { + return NULL; + } + p += nbytes_char; + bcnt -= nbytes_char; + } + } + return last; +} +/* }}} */ + +/* {{{ MBSTRING_API char *php_mb_safe_strrchr() */ +MBSTRING_API char *php_mb_safe_strrchr(const char *s, unsigned int c, size_t nbytes TSRMLS_DC) +{ + return php_mb_safe_strrchr_ex(s, c, nbytes, MBSTRG(internal_encoding)); +} +/* }}} */ + +/* {{{ MBSTRING_API int php_mb_stripos() + */ +MBSTRING_API int php_mb_stripos(int mode, const char *old_haystack, unsigned int old_haystack_len, const char *old_needle, unsigned int old_needle_len, long offset, const char *from_encoding TSRMLS_DC) +{ + int n; + mbfl_string haystack, needle; + n = -1; + + mbfl_string_init(&haystack); + mbfl_string_init(&needle); + haystack.no_language = MBSTRG(language); + haystack.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; + needle.no_language = MBSTRG(language); + needle.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; + + do { + size_t len = 0; + haystack.val = (unsigned char *)php_unicode_convert_case(PHP_UNICODE_CASE_UPPER, (char *)old_haystack, old_haystack_len, &len, from_encoding TSRMLS_CC); + haystack.len = len; + + if (!haystack.val) { + break; + } + + if (haystack.len <= 0) { + break; + } + + needle.val = (unsigned char *)php_unicode_convert_case(PHP_UNICODE_CASE_UPPER, (char *)old_needle, old_needle_len, &len, from_encoding TSRMLS_CC); + needle.len = len; + + if (!needle.val) { + break; + } + + if (needle.len <= 0) { + break; + } + + haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(from_encoding); + if (haystack.no_encoding == mbfl_no_encoding_invalid) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", from_encoding); + break; + } + + { + int haystack_char_len = mbfl_strlen(&haystack); + + if (mode) { + if ((offset > 0 && offset > haystack_char_len) || + (offset < 0 && -offset > haystack_char_len)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string"); + break; + } + } else { + if (offset < 0 || offset > haystack_char_len) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset not contained in string"); + break; + } + } + } + + n = mbfl_strpos(&haystack, &needle, offset, mode); + } while(0); + + if (haystack.val) { + efree(haystack.val); + } + + if (needle.val) { + efree(needle.val); + } + + return n; +} +/* }}} */ + +static void php_mb_gpc_get_detect_order(const zend_encoding ***list, size_t *list_size TSRMLS_DC) /* {{{ */ +{ + *list = (const zend_encoding **)MBSTRG(http_input_list); + *list_size = MBSTRG(http_input_list_size); +} +/* }}} */ + +static void php_mb_gpc_set_input_encoding(const zend_encoding *encoding TSRMLS_DC) /* {{{ */ +{ + MBSTRG(http_input_identify) = (const mbfl_encoding*)encoding; +} +/* }}} */ + +#endif /* HAVE_MBSTRING */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: fdm=marker + * vim: noet sw=4 ts=4 + */ |