File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / iconv / iconv.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 20:03:49 2014 UTC (10 years, 3 months ago) by misho
Branches: php, MAIN
CVS tags: v5_4_29, HEAD
php 5.4.29

    1: /*
    2:    +----------------------------------------------------------------------+
    3:    | PHP Version 5                                                        |
    4:    +----------------------------------------------------------------------+
    5:    | Copyright (c) 1997-2014 The PHP Group                                |
    6:    +----------------------------------------------------------------------+
    7:    | This source file is subject to version 3.01 of the PHP license,      |
    8:    | that is bundled with this package in the file LICENSE, and is        |
    9:    | available through the world-wide-web at the following url:           |
   10:    | http://www.php.net/license/3_01.txt                                  |
   11:    | If you did not receive a copy of the PHP license and are unable to   |
   12:    | obtain it through the world-wide-web, please send a note to          |
   13:    | license@php.net so we can mail you a copy immediately.               |
   14:    +----------------------------------------------------------------------+
   15:    | Authors: Rui Hirokawa <rui_hirokawa@ybb.ne.jp>                       |
   16:    |          Stig Bakken <ssb@php.net>                                   |
   17:    |          Moriyoshi Koizumi <moriyoshi@php.net>                       |
   18:    +----------------------------------------------------------------------+
   19:  */
   20: 
   21: /* $Id: iconv.c,v 1.1.1.4 2014/06/15 20:03:49 misho Exp $ */
   22: 
   23: #ifdef HAVE_CONFIG_H
   24: #include "config.h"
   25: #endif
   26: 
   27: #include "php.h"
   28: #include "php_globals.h"
   29: #include "ext/standard/info.h"
   30: #include "main/php_output.h"
   31: #include "SAPI.h"
   32: #include "php_ini.h"
   33: 
   34: #ifdef HAVE_STDLIB_H
   35: # include <stdlib.h>
   36: #endif
   37: 
   38: #include <errno.h>
   39: 
   40: #include "php_iconv.h"
   41: 
   42: #ifdef HAVE_ICONV
   43: 
   44: #ifdef PHP_ICONV_H_PATH
   45: #include PHP_ICONV_H_PATH
   46: #else
   47: #include <iconv.h>
   48: #endif
   49: 
   50: #ifdef HAVE_GLIBC_ICONV
   51: #include <gnu/libc-version.h>
   52: #endif
   53: 
   54: #ifdef HAVE_LIBICONV
   55: #undef iconv
   56: #endif
   57: 
   58: #include "ext/standard/php_smart_str.h"
   59: #include "ext/standard/base64.h"
   60: #include "ext/standard/quot_print.h"
   61: 
   62: #define _php_iconv_memequal(a, b, c) \
   63:   ((c) == sizeof(unsigned long) ? *((unsigned long *)(a)) == *((unsigned long *)(b)) : ((c) == sizeof(unsigned int) ? *((unsigned int *)(a)) == *((unsigned int *)(b)) : memcmp(a, b, c) == 0))
   64: 
   65: /* {{{ arginfo */
   66: ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_strlen, 0, 0, 1)
   67: 	ZEND_ARG_INFO(0, str)
   68: 	ZEND_ARG_INFO(0, charset)
   69: ZEND_END_ARG_INFO()
   70: 
   71: ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_substr, 0, 0, 2)
   72: 	ZEND_ARG_INFO(0, str)
   73: 	ZEND_ARG_INFO(0, offset)
   74: 	ZEND_ARG_INFO(0, length)
   75: 	ZEND_ARG_INFO(0, charset)
   76: ZEND_END_ARG_INFO()
   77: 
   78: ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_strpos, 0, 0, 2)
   79: 	ZEND_ARG_INFO(0, haystack)
   80: 	ZEND_ARG_INFO(0, needle)
   81: 	ZEND_ARG_INFO(0, offset)
   82: 	ZEND_ARG_INFO(0, charset)
   83: ZEND_END_ARG_INFO()
   84: 
   85: ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_strrpos, 0, 0, 2)
   86: 	ZEND_ARG_INFO(0, haystack)
   87: 	ZEND_ARG_INFO(0, needle)
   88: 	ZEND_ARG_INFO(0, charset)
   89: ZEND_END_ARG_INFO()
   90: 
   91: ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_mime_encode, 0, 0, 2)
   92: 	ZEND_ARG_INFO(0, field_name)
   93: 	ZEND_ARG_INFO(0, field_value)
   94: 	ZEND_ARG_INFO(0, preference) /* ZEND_ARG_ARRAY_INFO(0, preference, 1) */
   95: ZEND_END_ARG_INFO()
   96: 
   97: ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_mime_decode, 0, 0, 1)
   98: 	ZEND_ARG_INFO(0, encoded_string)
   99: 	ZEND_ARG_INFO(0, mode)
  100: 	ZEND_ARG_INFO(0, charset)
  101: ZEND_END_ARG_INFO()
  102: 
  103: ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_mime_decode_headers, 0, 0, 1)
  104: 	ZEND_ARG_INFO(0, headers)
  105: 	ZEND_ARG_INFO(0, mode)
  106: 	ZEND_ARG_INFO(0, charset)
  107: ZEND_END_ARG_INFO()
  108: 
  109: ZEND_BEGIN_ARG_INFO(arginfo_iconv, 0)
  110: 	ZEND_ARG_INFO(0, in_charset)
  111: 	ZEND_ARG_INFO(0, out_charset)
  112: 	ZEND_ARG_INFO(0, str)
  113: ZEND_END_ARG_INFO()
  114: 
  115: ZEND_BEGIN_ARG_INFO(arginfo_iconv_set_encoding, 0)
  116: 	ZEND_ARG_INFO(0, type)
  117: 	ZEND_ARG_INFO(0, charset)
  118: ZEND_END_ARG_INFO()
  119: 
  120: ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_get_encoding, 0, 0, 0)
  121: 	ZEND_ARG_INFO(0, type)
  122: ZEND_END_ARG_INFO()
  123: 
  124: /* }}} */
  125: 
  126: /* {{{ iconv_functions[]
  127:  */
  128: const zend_function_entry iconv_functions[] = {
  129: 	PHP_RAW_NAMED_FE(iconv,php_if_iconv,				arginfo_iconv)
  130: 	PHP_FE(iconv_get_encoding,						arginfo_iconv_get_encoding)
  131: 	PHP_FE(iconv_set_encoding,						arginfo_iconv_set_encoding)
  132: 	PHP_FE(iconv_strlen,							arginfo_iconv_strlen)
  133: 	PHP_FE(iconv_substr,							arginfo_iconv_substr)
  134: 	PHP_FE(iconv_strpos,							arginfo_iconv_strpos)
  135: 	PHP_FE(iconv_strrpos,							arginfo_iconv_strrpos)
  136: 	PHP_FE(iconv_mime_encode,						arginfo_iconv_mime_encode)
  137: 	PHP_FE(iconv_mime_decode,						arginfo_iconv_mime_decode)
  138: 	PHP_FE(iconv_mime_decode_headers,				arginfo_iconv_mime_decode_headers)
  139: 	PHP_FE_END
  140: };
  141: /* }}} */
  142: 
  143: ZEND_DECLARE_MODULE_GLOBALS(iconv)
  144: static PHP_GINIT_FUNCTION(iconv);
  145: 
  146: /* {{{ iconv_module_entry
  147:  */
  148: zend_module_entry iconv_module_entry = {
  149: 	STANDARD_MODULE_HEADER,
  150: 	"iconv",
  151: 	iconv_functions,
  152: 	PHP_MINIT(miconv),
  153: 	PHP_MSHUTDOWN(miconv),
  154: 	NULL,
  155: 	NULL,
  156: 	PHP_MINFO(miconv),
  157: 	NO_VERSION_YET,
  158: 	PHP_MODULE_GLOBALS(iconv),
  159: 	PHP_GINIT(iconv),
  160: 	NULL,
  161: 	NULL,
  162: 	STANDARD_MODULE_PROPERTIES_EX
  163: };
  164: /* }}} */
  165: 
  166: #ifdef COMPILE_DL_ICONV
  167: ZEND_GET_MODULE(iconv)
  168: #endif
  169: 
  170: /* {{{ PHP_GINIT_FUNCTION */
  171: static PHP_GINIT_FUNCTION(iconv)
  172: {
  173: 	iconv_globals->input_encoding = NULL;
  174: 	iconv_globals->output_encoding = NULL;
  175: 	iconv_globals->internal_encoding = NULL;
  176: }
  177: /* }}} */
  178: 
  179: #if defined(HAVE_LIBICONV) && defined(ICONV_ALIASED_LIBICONV)
  180: #define iconv libiconv
  181: #endif
  182: 
  183: /* {{{ typedef enum php_iconv_enc_scheme_t */
  184: typedef enum _php_iconv_enc_scheme_t {
  185: 	PHP_ICONV_ENC_SCHEME_BASE64,
  186: 	PHP_ICONV_ENC_SCHEME_QPRINT
  187: } php_iconv_enc_scheme_t;
  188: /* }}} */
  189: 
  190: #define PHP_ICONV_MIME_DECODE_STRICT            (1<<0)
  191: #define PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR (1<<1)
  192: 
  193: /* {{{ prototypes */
  194: static php_iconv_err_t _php_iconv_appendl(smart_str *d, const char *s, size_t l, iconv_t cd);
  195: static php_iconv_err_t _php_iconv_appendc(smart_str *d, const char c, iconv_t cd);
  196: 
  197: static void _php_iconv_show_error(php_iconv_err_t err, const char *out_charset, const char *in_charset TSRMLS_DC);
  198: 
  199: static php_iconv_err_t _php_iconv_strlen(unsigned int *pretval, const char *str, size_t nbytes, const char *enc);
  200: 
  201: static php_iconv_err_t _php_iconv_substr(smart_str *pretval, const char *str, size_t nbytes, int offset, int len, const char *enc);
  202: 
  203: static php_iconv_err_t _php_iconv_strpos(unsigned int *pretval, const char *haystk, size_t haystk_nbytes, const char *ndl, size_t ndl_nbytes, int offset, const char *enc);
  204: 
  205: static php_iconv_err_t _php_iconv_mime_encode(smart_str *pretval, const char *fname, size_t fname_nbytes, const char *fval, size_t fval_nbytes, unsigned int max_line_len, const char *lfchars, php_iconv_enc_scheme_t enc_scheme, const char *out_charset, const char *enc);
  206: 
  207: static php_iconv_err_t _php_iconv_mime_decode(smart_str *pretval, const char *str, size_t str_nbytes, const char *enc, const char **next_pos, int mode);
  208: 
  209: static php_iconv_err_t php_iconv_stream_filter_register_factory(TSRMLS_D);
  210: static php_iconv_err_t php_iconv_stream_filter_unregister_factory(TSRMLS_D);
  211: 
  212: static int php_iconv_output_conflict(const char *handler_name, size_t handler_name_len TSRMLS_DC);
  213: static php_output_handler *php_iconv_output_handler_init(const char *name, size_t name_len, size_t chunk_size, int flags TSRMLS_DC);
  214: static int php_iconv_output_handler(void **nothing, php_output_context *output_context);
  215: /* }}} */
  216: 
  217: /* {{{ static globals */
  218: static char _generic_superset_name[] = ICONV_UCS4_ENCODING;
  219: #define GENERIC_SUPERSET_NAME _generic_superset_name
  220: #define GENERIC_SUPERSET_NBYTES 4
  221: /* }}} */
  222: 
  223: static PHP_INI_MH(OnUpdateStringIconvCharset)
  224: {
  225: 	if(new_value_length >= ICONV_CSNMAXLEN) {
  226: 		return FAILURE;
  227: 	}
  228: 	OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
  229: 	return SUCCESS;
  230: }
  231: 
  232: /* {{{ PHP_INI
  233:  */
  234: PHP_INI_BEGIN()
  235: 	STD_PHP_INI_ENTRY("iconv.input_encoding",    ICONV_INPUT_ENCODING,    PHP_INI_ALL, OnUpdateStringIconvCharset, input_encoding,    zend_iconv_globals, iconv_globals)
  236: 	STD_PHP_INI_ENTRY("iconv.output_encoding",   ICONV_OUTPUT_ENCODING,   PHP_INI_ALL, OnUpdateStringIconvCharset, output_encoding,   zend_iconv_globals, iconv_globals)
  237: 	STD_PHP_INI_ENTRY("iconv.internal_encoding", ICONV_INTERNAL_ENCODING, PHP_INI_ALL, OnUpdateStringIconvCharset, internal_encoding, zend_iconv_globals, iconv_globals)
  238: PHP_INI_END()
  239: /* }}} */
  240: 
  241: /* {{{ PHP_MINIT_FUNCTION */
  242: PHP_MINIT_FUNCTION(miconv)
  243: {
  244: 	char *version = "unknown";
  245: 
  246: 	REGISTER_INI_ENTRIES();
  247: 
  248: #if HAVE_LIBICONV
  249: 	{
  250: 		static char buf[16];
  251: 		snprintf(buf, sizeof(buf), "%d.%d",
  252: 		    ((_libiconv_version >> 8) & 0x0f), (_libiconv_version & 0x0f));
  253: 		version = buf;
  254: 	}
  255: #elif HAVE_GLIBC_ICONV
  256: 	version = (char *)gnu_get_libc_version();
  257: #elif defined(NETWARE)
  258: 	version = "OS built-in";
  259: #endif
  260: 
  261: #ifdef PHP_ICONV_IMPL
  262: 	REGISTER_STRING_CONSTANT("ICONV_IMPL", PHP_ICONV_IMPL, CONST_CS | CONST_PERSISTENT);
  263: #elif HAVE_LIBICONV
  264: 	REGISTER_STRING_CONSTANT("ICONV_IMPL", "libiconv", CONST_CS | CONST_PERSISTENT);
  265: #elif defined(NETWARE)
  266: 	REGISTER_STRING_CONSTANT("ICONV_IMPL", "Novell", CONST_CS | CONST_PERSISTENT);
  267: #else
  268: 	REGISTER_STRING_CONSTANT("ICONV_IMPL", "unknown", CONST_CS | CONST_PERSISTENT);
  269: #endif
  270: 	REGISTER_STRING_CONSTANT("ICONV_VERSION", version, CONST_CS | CONST_PERSISTENT);
  271: 
  272: 	REGISTER_LONG_CONSTANT("ICONV_MIME_DECODE_STRICT", PHP_ICONV_MIME_DECODE_STRICT, CONST_CS | CONST_PERSISTENT);
  273: 	REGISTER_LONG_CONSTANT("ICONV_MIME_DECODE_CONTINUE_ON_ERROR", PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR, CONST_CS | CONST_PERSISTENT);
  274: 
  275: 	if (php_iconv_stream_filter_register_factory(TSRMLS_C) != PHP_ICONV_ERR_SUCCESS) {
  276: 		return FAILURE;
  277: 	}
  278: 
  279: 	php_output_handler_alias_register(ZEND_STRL("ob_iconv_handler"), php_iconv_output_handler_init TSRMLS_CC);
  280: 	php_output_handler_conflict_register(ZEND_STRL("ob_iconv_handler"), php_iconv_output_conflict TSRMLS_CC);
  281: 
  282: 	return SUCCESS;
  283: }
  284: /* }}} */
  285: 
  286: /* {{{ PHP_MSHUTDOWN_FUNCTION */
  287: PHP_MSHUTDOWN_FUNCTION(miconv)
  288: {
  289: 	php_iconv_stream_filter_unregister_factory(TSRMLS_C);
  290: 	UNREGISTER_INI_ENTRIES();
  291: 	return SUCCESS;
  292: }
  293: /* }}} */
  294: 
  295: /* {{{ PHP_MINFO_FUNCTION */
  296: PHP_MINFO_FUNCTION(miconv)
  297: {
  298: 	zval iconv_impl, iconv_ver;
  299: 
  300: 	zend_get_constant("ICONV_IMPL", sizeof("ICONV_IMPL")-1, &iconv_impl TSRMLS_CC);
  301: 	zend_get_constant("ICONV_VERSION", sizeof("ICONV_VERSION")-1, &iconv_ver TSRMLS_CC);
  302: 
  303: 	php_info_print_table_start();
  304: 	php_info_print_table_row(2, "iconv support", "enabled");
  305: 	php_info_print_table_row(2, "iconv implementation", Z_STRVAL(iconv_impl));
  306: 	php_info_print_table_row(2, "iconv library version", Z_STRVAL(iconv_ver));
  307: 	php_info_print_table_end();
  308: 
  309: 	DISPLAY_INI_ENTRIES();
  310: 
  311: 	zval_dtor(&iconv_impl);
  312: 	zval_dtor(&iconv_ver);
  313: }
  314: /* }}} */
  315: 
  316: static int php_iconv_output_conflict(const char *handler_name, size_t handler_name_len TSRMLS_DC)
  317: {
  318: 	if (php_output_get_level(TSRMLS_C)) {
  319: 		if (php_output_handler_conflict(handler_name, handler_name_len, ZEND_STRL("ob_iconv_handler") TSRMLS_CC)
  320: 		||	php_output_handler_conflict(handler_name, handler_name_len, ZEND_STRL("mb_output_handler") TSRMLS_CC)) {
  321: 			return FAILURE;
  322: 		}
  323: 	}
  324: 	return SUCCESS;
  325: }
  326: 
  327: static php_output_handler *php_iconv_output_handler_init(const char *handler_name, size_t handler_name_len, size_t chunk_size, int flags TSRMLS_DC)
  328: {
  329: 	return php_output_handler_create_internal(handler_name, handler_name_len, php_iconv_output_handler, chunk_size, flags TSRMLS_CC);
  330: }
  331: 
  332: static int php_iconv_output_handler(void **nothing, php_output_context *output_context)
  333: {
  334: 	char *s, *content_type, *mimetype = NULL;
  335: 	int output_status, mimetype_len = 0;
  336: 	PHP_OUTPUT_TSRMLS(output_context);
  337: 
  338: 	if (output_context->op & PHP_OUTPUT_HANDLER_START) {
  339: 		output_status = php_output_get_status(TSRMLS_C);
  340: 		if (output_status & PHP_OUTPUT_SENT) {
  341: 			return FAILURE;
  342: 		}
  343: 
  344: 		if (SG(sapi_headers).mimetype && !strncasecmp(SG(sapi_headers).mimetype, "text/", 5)) {
  345: 			if ((s = strchr(SG(sapi_headers).mimetype,';')) == NULL){
  346: 				mimetype = SG(sapi_headers).mimetype;
  347: 			} else {
  348: 				mimetype = SG(sapi_headers).mimetype;
  349: 				mimetype_len = s - SG(sapi_headers).mimetype;
  350: 			}
  351: 		} else if (SG(sapi_headers).send_default_content_type) {
  352: 			mimetype = SG(default_mimetype) ? SG(default_mimetype) : SAPI_DEFAULT_MIMETYPE;
  353: 		}
  354: 
  355: 		if (mimetype != NULL && !(output_context->op & PHP_OUTPUT_HANDLER_CLEAN)) {
  356: 			int len;
  357: 			char *p = strstr(ICONVG(output_encoding), "//");
  358: 
  359: 			if (p) {
  360: 				len = spprintf(&content_type, 0, "Content-Type:%.*s; charset=%.*s", mimetype_len ? mimetype_len : (int) strlen(mimetype), mimetype, (int)(p - ICONVG(output_encoding)), ICONVG(output_encoding));
  361: 			} else {
  362: 				len = spprintf(&content_type, 0, "Content-Type:%.*s; charset=%s", mimetype_len ? mimetype_len : (int) strlen(mimetype), mimetype, ICONVG(output_encoding));
  363: 			}
  364: 			if (content_type && SUCCESS == sapi_add_header(content_type, len, 0)) {
  365: 				SG(sapi_headers).send_default_content_type = 0;
  366: 				php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE, NULL TSRMLS_CC);
  367: 			}
  368: 		}
  369: 	}
  370: 
  371: 	if (output_context->in.used) {
  372: 		output_context->out.free = 1;
  373: 		_php_iconv_show_error(php_iconv_string(output_context->in.data, output_context->in.used, &output_context->out.data, &output_context->out.used, ICONVG(output_encoding), ICONVG(internal_encoding)), ICONVG(output_encoding), ICONVG(internal_encoding) TSRMLS_CC);
  374: 	}
  375: 
  376: 	return SUCCESS;
  377: }
  378: 
  379: /* {{{ _php_iconv_appendl() */
  380: static php_iconv_err_t _php_iconv_appendl(smart_str *d, const char *s, size_t l, iconv_t cd)
  381: {
  382: 	const char *in_p = s;
  383: 	size_t in_left = l;
  384: 	char *out_p;
  385: 	size_t out_left = 0;
  386: 	size_t buf_growth = 128;
  387: #if !ICONV_SUPPORTS_ERRNO
  388: 	size_t prev_in_left = in_left;
  389: #endif
  390: 
  391: 	if (in_p != NULL) {
  392: 		while (in_left > 0) {
  393: 			out_left = buf_growth - out_left;
  394: 			{
  395: 				size_t newlen;
  396: 				smart_str_alloc((d), out_left, 0);
  397: 			}
  398: 
  399: 			out_p = (d)->c + (d)->len;
  400: 
  401: 			if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
  402: #if ICONV_SUPPORTS_ERRNO
  403: 				switch (errno) {
  404: 					case EINVAL:
  405: 						return PHP_ICONV_ERR_ILLEGAL_CHAR;
  406: 
  407: 					case EILSEQ:
  408: 						return PHP_ICONV_ERR_ILLEGAL_SEQ;
  409: 
  410: 					case E2BIG:
  411: 						break;
  412: 
  413: 					default:
  414: 						return PHP_ICONV_ERR_UNKNOWN;
  415: 				}
  416: #else
  417: 				if (prev_in_left == in_left) {
  418: 					return PHP_ICONV_ERR_UNKNOWN;
  419: 				}
  420: #endif
  421: 			}
  422: #if !ICONV_SUPPORTS_ERRNO
  423: 			prev_in_left = in_left;
  424: #endif
  425: 			(d)->len += (buf_growth - out_left);
  426: 			buf_growth <<= 1;
  427: 		}
  428: 	} else {
  429: 		for (;;) {
  430: 			out_left = buf_growth - out_left;
  431: 			{
  432: 				size_t newlen;
  433: 				smart_str_alloc((d), out_left, 0);
  434: 			}
  435: 
  436: 			out_p = (d)->c + (d)->len;
  437: 
  438: 			if (iconv(cd, NULL, NULL, (char **) &out_p, &out_left) == (size_t)0) {
  439: 				(d)->len += (buf_growth - out_left);
  440: 				break;
  441: 			} else {
  442: #if ICONV_SUPPORTS_ERRNO
  443: 				if (errno != E2BIG) {
  444: 					return PHP_ICONV_ERR_UNKNOWN;
  445: 				}
  446: #else
  447: 				if (out_left != 0) {
  448: 					return PHP_ICONV_ERR_UNKNOWN;
  449: 				}
  450: #endif
  451: 			}
  452: 			(d)->len += (buf_growth - out_left);
  453: 			buf_growth <<= 1;
  454: 		}
  455: 	}
  456: 	return PHP_ICONV_ERR_SUCCESS;
  457: }
  458: /* }}} */
  459: 
  460: /* {{{ _php_iconv_appendc() */
  461: static php_iconv_err_t _php_iconv_appendc(smart_str *d, const char c, iconv_t cd)
  462: {
  463: 	return _php_iconv_appendl(d, &c, 1, cd);
  464: }
  465: /* }}} */
  466: 
  467: /* {{{ php_iconv_string()
  468:  */
  469: PHP_ICONV_API php_iconv_err_t php_iconv_string(const char *in_p, size_t in_len,
  470: 							char **out, size_t *out_len,
  471: 							const char *out_charset, const char *in_charset)
  472: {
  473: #if !ICONV_SUPPORTS_ERRNO
  474: 	size_t in_size, out_size, out_left;
  475: 	char *out_buffer, *out_p;
  476: 	iconv_t cd;
  477: 	size_t result;
  478: 
  479: 	*out = NULL;
  480: 	*out_len = 0;
  481: 
  482: 	/*
  483: 	  This is not the right way to get output size...
  484: 	  This is not space efficient for large text.
  485: 	  This is also problem for encoding like UTF-7/UTF-8/ISO-2022 which
  486: 	  a single char can be more than 4 bytes.
  487: 	  I added 15 extra bytes for safety. <yohgaki@php.net>
  488: 	*/
  489: 	out_size = in_len * sizeof(int) + 15;
  490: 	out_left = out_size;
  491: 
  492: 	in_size = in_len;
  493: 
  494: 	cd = iconv_open(out_charset, in_charset);
  495: 
  496: 	if (cd == (iconv_t)(-1)) {
  497: 		return PHP_ICONV_ERR_UNKNOWN;
  498: 	}
  499: 
  500: 	out_buffer = (char *) emalloc(out_size + 1);
  501: 	out_p = out_buffer;
  502: 
  503: #ifdef NETWARE
  504: 	result = iconv(cd, (char **) &in_p, &in_size, (char **)
  505: #else
  506: 	result = iconv(cd, (const char **) &in_p, &in_size, (char **)
  507: #endif
  508: 				&out_p, &out_left);
  509: 
  510: 	if (result == (size_t)(-1)) {
  511: 		efree(out_buffer);
  512: 		return PHP_ICONV_ERR_UNKNOWN;
  513: 	}
  514: 
  515: 	if (out_left < 8) {
  516: 		size_t pos = out_p - out_buffer;
  517: 		out_buffer = (char *) safe_erealloc(out_buffer, out_size, 1, 8);
  518: 		out_p = out_buffer+pos;
  519: 		out_size += 7;
  520: 		out_left += 7;
  521: 	}
  522: 
  523: 	/* flush the shift-out sequences */
  524: 	result = iconv(cd, NULL, NULL, &out_p, &out_left);
  525: 
  526: 	if (result == (size_t)(-1)) {
  527: 		efree(out_buffer);
  528: 		return PHP_ICONV_ERR_UNKNOWN;
  529: 	}
  530: 
  531: 	*out_len = out_size - out_left;
  532: 	out_buffer[*out_len] = '\0';
  533: 	*out = out_buffer;
  534: 
  535: 	iconv_close(cd);
  536: 
  537: 	return PHP_ICONV_ERR_SUCCESS;
  538: 
  539: #else
  540: 	/*
  541: 	  iconv supports errno. Handle it better way.
  542: 	*/
  543: 	iconv_t cd;
  544: 	size_t in_left, out_size, out_left;
  545: 	char *out_p, *out_buf, *tmp_buf;
  546: 	size_t bsz, result = 0;
  547: 	php_iconv_err_t retval = PHP_ICONV_ERR_SUCCESS;
  548: 
  549: 	*out = NULL;
  550: 	*out_len = 0;
  551: 
  552: 	cd = iconv_open(out_charset, in_charset);
  553: 
  554: 	if (cd == (iconv_t)(-1)) {
  555: 		if (errno == EINVAL) {
  556: 			return PHP_ICONV_ERR_WRONG_CHARSET;
  557: 		} else {
  558: 			return PHP_ICONV_ERR_CONVERTER;
  559: 		}
  560: 	}
  561: 	in_left= in_len;
  562: 	out_left = in_len + 32; /* Avoid realloc() most cases */
  563: 	out_size = 0;
  564: 	bsz = out_left;
  565: 	out_buf = (char *) emalloc(bsz+1);
  566: 	out_p = out_buf;
  567: 
  568: 	while (in_left > 0) {
  569: 		result = iconv(cd, (char **) &in_p, &in_left, (char **) &out_p, &out_left);
  570: 		out_size = bsz - out_left;
  571: 		if (result == (size_t)(-1)) {
  572: 			if (errno == E2BIG && in_left > 0) {
  573: 				/* converted string is longer than out buffer */
  574: 				bsz += in_len;
  575: 
  576: 				tmp_buf = (char*) erealloc(out_buf, bsz+1);
  577: 				out_p = out_buf = tmp_buf;
  578: 				out_p += out_size;
  579: 				out_left = bsz - out_size;
  580: 				continue;
  581: 			}
  582: 		}
  583: 		break;
  584: 	}
  585: 
  586: 	if (result != (size_t)(-1)) {
  587: 		/* flush the shift-out sequences */
  588: 		for (;;) {
  589: 		   	result = iconv(cd, NULL, NULL, (char **) &out_p, &out_left);
  590: 			out_size = bsz - out_left;
  591: 
  592: 			if (result != (size_t)(-1)) {
  593: 				break;
  594: 			}
  595: 
  596: 			if (errno == E2BIG) {
  597: 				bsz += 16;
  598: 				tmp_buf = (char *) erealloc(out_buf, bsz);
  599: 
  600: 				out_p = out_buf = tmp_buf;
  601: 				out_p += out_size;
  602: 				out_left = bsz - out_size;
  603: 			} else {
  604: 				break;
  605: 			}
  606: 		}
  607: 	}
  608: 
  609: 	iconv_close(cd);
  610: 
  611: 	if (result == (size_t)(-1)) {
  612: 		switch (errno) {
  613: 			case EINVAL:
  614: 				retval = PHP_ICONV_ERR_ILLEGAL_CHAR;
  615: 				break;
  616: 
  617: 			case EILSEQ:
  618: 				retval = PHP_ICONV_ERR_ILLEGAL_SEQ;
  619: 				break;
  620: 
  621: 			case E2BIG:
  622: 				/* should not happen */
  623: 				retval = PHP_ICONV_ERR_TOO_BIG;
  624: 				break;
  625: 
  626: 			default:
  627: 				/* other error */
  628: 				retval = PHP_ICONV_ERR_UNKNOWN;
  629: 				efree(out_buf);
  630: 				return PHP_ICONV_ERR_UNKNOWN;
  631: 		}
  632: 	}
  633: 	*out_p = '\0';
  634: 	*out = out_buf;
  635: 	*out_len = out_size;
  636: 	return retval;
  637: #endif
  638: }
  639: /* }}} */
  640: 
  641: /* {{{ _php_iconv_strlen() */
  642: static php_iconv_err_t _php_iconv_strlen(unsigned int *pretval, const char *str, size_t nbytes, const char *enc)
  643: {
  644: 	char buf[GENERIC_SUPERSET_NBYTES*2];
  645: 
  646: 	php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS;
  647: 
  648: 	iconv_t cd;
  649: 
  650: 	const char *in_p;
  651: 	size_t in_left;
  652: 
  653: 	char *out_p;
  654: 	size_t out_left;
  655: 
  656: 	unsigned int cnt;
  657: 
  658: 	*pretval = (unsigned int)-1;
  659: 
  660: 	cd = iconv_open(GENERIC_SUPERSET_NAME, enc);
  661: 
  662: 	if (cd == (iconv_t)(-1)) {
  663: #if ICONV_SUPPORTS_ERRNO
  664: 		if (errno == EINVAL) {
  665: 			return PHP_ICONV_ERR_WRONG_CHARSET;
  666: 		} else {
  667: 			return PHP_ICONV_ERR_CONVERTER;
  668: 		}
  669: #else
  670: 		return PHP_ICONV_ERR_UNKNOWN;
  671: #endif
  672: 	}
  673: 
  674: 	errno = out_left = 0;
  675: 
  676: 	for (in_p = str, in_left = nbytes, cnt = 0; in_left > 0; cnt+=2) {
  677: 		size_t prev_in_left;
  678: 		out_p = buf;
  679: 		out_left = sizeof(buf);
  680: 
  681: 		prev_in_left = in_left;
  682: 
  683: 		if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
  684: 			if (prev_in_left == in_left) {
  685: 				break;
  686: 			}
  687: 		}
  688: 	}
  689: 
  690: 	if (out_left > 0) {
  691: 		cnt -= out_left / GENERIC_SUPERSET_NBYTES;
  692: 	}
  693: 
  694: #if ICONV_SUPPORTS_ERRNO
  695: 	switch (errno) {
  696: 		case EINVAL:
  697: 			err = PHP_ICONV_ERR_ILLEGAL_CHAR;
  698: 			break;
  699: 
  700: 		case EILSEQ:
  701: 			err = PHP_ICONV_ERR_ILLEGAL_SEQ;
  702: 			break;
  703: 
  704: 		case E2BIG:
  705: 		case 0:
  706: 			*pretval = cnt;
  707: 			break;
  708: 
  709: 		default:
  710: 			err = PHP_ICONV_ERR_UNKNOWN;
  711: 			break;
  712: 	}
  713: #else
  714: 	*pretval = cnt;
  715: #endif
  716: 
  717: 	iconv_close(cd);
  718: 
  719: 	return err;
  720: }
  721: 
  722: /* }}} */
  723: 
  724: /* {{{ _php_iconv_substr() */
  725: static php_iconv_err_t _php_iconv_substr(smart_str *pretval,
  726: 	const char *str, size_t nbytes, int offset, int len, const char *enc)
  727: {
  728: 	char buf[GENERIC_SUPERSET_NBYTES];
  729: 
  730: 	php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS;
  731: 
  732: 	iconv_t cd1, cd2;
  733: 
  734: 	const char *in_p;
  735: 	size_t in_left;
  736: 
  737: 	char *out_p;
  738: 	size_t out_left;
  739: 
  740: 	unsigned int cnt;
  741: 	int total_len;
  742: 
  743: 	err = _php_iconv_strlen(&total_len, str, nbytes, enc);
  744: 	if (err != PHP_ICONV_ERR_SUCCESS) {
  745: 		return err;
  746: 	}
  747: 
  748: 	if (len < 0) {
  749: 		if ((len += (total_len - offset)) < 0) {
  750: 			return PHP_ICONV_ERR_SUCCESS;
  751: 		}
  752: 	}
  753: 
  754: 	if (offset < 0) {
  755: 		if ((offset += total_len) < 0) {
  756: 			return PHP_ICONV_ERR_SUCCESS;
  757: 		}
  758: 	}
  759: 
  760: 	if(len > total_len) {
  761: 		len = total_len;
  762: 	}
  763: 
  764: 
  765: 	if (offset >= total_len) {
  766: 		return PHP_ICONV_ERR_SUCCESS;
  767: 	}
  768: 
  769: 	if ((offset + len) > total_len ) {
  770: 		/* trying to compute the length */
  771: 		len = total_len - offset;
  772: 	}
  773: 
  774: 	if (len == 0) {
  775: 		smart_str_appendl(pretval, "", 0);
  776: 		smart_str_0(pretval);
  777: 		return PHP_ICONV_ERR_SUCCESS;
  778: 	}
  779: 
  780: 	cd1 = iconv_open(GENERIC_SUPERSET_NAME, enc);
  781: 
  782: 	if (cd1 == (iconv_t)(-1)) {
  783: #if ICONV_SUPPORTS_ERRNO
  784: 		if (errno == EINVAL) {
  785: 			return PHP_ICONV_ERR_WRONG_CHARSET;
  786: 		} else {
  787: 			return PHP_ICONV_ERR_CONVERTER;
  788: 		}
  789: #else
  790: 		return PHP_ICONV_ERR_UNKNOWN;
  791: #endif
  792: 	}
  793: 
  794: 	cd2 = (iconv_t)NULL;
  795: 	errno = 0;
  796: 
  797: 	for (in_p = str, in_left = nbytes, cnt = 0; in_left > 0 && len > 0; ++cnt) {
  798: 		size_t prev_in_left;
  799: 		out_p = buf;
  800: 		out_left = sizeof(buf);
  801: 
  802: 		prev_in_left = in_left;
  803: 
  804: 		if (iconv(cd1, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
  805: 			if (prev_in_left == in_left) {
  806: 				break;
  807: 			}
  808: 		}
  809: 
  810: 		if (cnt >= (unsigned int)offset) {
  811: 			if (cd2 == (iconv_t)NULL) {
  812: 				cd2 = iconv_open(enc, GENERIC_SUPERSET_NAME);
  813: 
  814: 				if (cd2 == (iconv_t)(-1)) {
  815: 					cd2 = (iconv_t)NULL;
  816: #if ICONV_SUPPORTS_ERRNO
  817: 					if (errno == EINVAL) {
  818: 						err = PHP_ICONV_ERR_WRONG_CHARSET;
  819: 					} else {
  820: 						err = PHP_ICONV_ERR_CONVERTER;
  821: 					}
  822: #else
  823: 					err = PHP_ICONV_ERR_UNKNOWN;
  824: #endif
  825: 					break;
  826: 				}
  827: 			}
  828: 
  829: 			if (_php_iconv_appendl(pretval, buf, sizeof(buf), cd2) != PHP_ICONV_ERR_SUCCESS) {
  830: 				break;
  831: 			}
  832: 			--len;
  833: 		}
  834: 
  835: 	}
  836: 
  837: #if ICONV_SUPPORTS_ERRNO
  838: 	switch (errno) {
  839: 		case EINVAL:
  840: 			err = PHP_ICONV_ERR_ILLEGAL_CHAR;
  841: 			break;
  842: 
  843: 		case EILSEQ:
  844: 			err = PHP_ICONV_ERR_ILLEGAL_SEQ;
  845: 			break;
  846: 
  847: 		case E2BIG:
  848: 			break;
  849: 	}
  850: #endif
  851: 	if (err == PHP_ICONV_ERR_SUCCESS) {
  852: 		if (cd2 != (iconv_t)NULL) {
  853: 			_php_iconv_appendl(pretval, NULL, 0, cd2);
  854: 		}
  855: 		smart_str_0(pretval);
  856: 	}
  857: 
  858: 	if (cd1 != (iconv_t)NULL) {
  859: 		iconv_close(cd1);
  860: 	}
  861: 
  862: 	if (cd2 != (iconv_t)NULL) {
  863: 		iconv_close(cd2);
  864: 	}
  865: 	return err;
  866: }
  867: 
  868: /* }}} */
  869: 
  870: /* {{{ _php_iconv_strpos() */
  871: static php_iconv_err_t _php_iconv_strpos(unsigned int *pretval,
  872: 	const char *haystk, size_t haystk_nbytes,
  873: 	const char *ndl, size_t ndl_nbytes,
  874: 	int offset, const char *enc)
  875: {
  876: 	char buf[GENERIC_SUPERSET_NBYTES];
  877: 
  878: 	php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS;
  879: 
  880: 	iconv_t cd;
  881: 
  882: 	const char *in_p;
  883: 	size_t in_left;
  884: 
  885: 	char *out_p;
  886: 	size_t out_left;
  887: 
  888: 	unsigned int cnt;
  889: 
  890: 	char *ndl_buf;
  891: 	const char *ndl_buf_p;
  892: 	size_t ndl_buf_len, ndl_buf_left;
  893: 
  894: 	unsigned int match_ofs;
  895: 
  896: 	*pretval = (unsigned int)-1;
  897: 
  898: 	err = php_iconv_string(ndl, ndl_nbytes,
  899: 		&ndl_buf, &ndl_buf_len, GENERIC_SUPERSET_NAME, enc);
  900: 
  901: 	if (err != PHP_ICONV_ERR_SUCCESS) {
  902: 		if (ndl_buf != NULL) {
  903: 			efree(ndl_buf);
  904: 		}
  905: 		return err;
  906: 	}
  907: 
  908: 	cd = iconv_open(GENERIC_SUPERSET_NAME, enc);
  909: 
  910: 	if (cd == (iconv_t)(-1)) {
  911: 		if (ndl_buf != NULL) {
  912: 			efree(ndl_buf);
  913: 		}
  914: #if ICONV_SUPPORTS_ERRNO
  915: 		if (errno == EINVAL) {
  916: 			return PHP_ICONV_ERR_WRONG_CHARSET;
  917: 		} else {
  918: 			return PHP_ICONV_ERR_CONVERTER;
  919: 		}
  920: #else
  921: 		return PHP_ICONV_ERR_UNKNOWN;
  922: #endif
  923: 	}
  924: 
  925: 	ndl_buf_p = ndl_buf;
  926: 	ndl_buf_left = ndl_buf_len;
  927: 	match_ofs = (unsigned int)-1;
  928: 
  929: 	for (in_p = haystk, in_left = haystk_nbytes, cnt = 0; in_left > 0; ++cnt) {
  930: 		size_t prev_in_left;
  931: 		out_p = buf;
  932: 		out_left = sizeof(buf);
  933: 
  934: 		prev_in_left = in_left;
  935: 
  936: 		if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
  937: 			if (prev_in_left == in_left) {
  938: #if ICONV_SUPPORTS_ERRNO
  939: 				switch (errno) {
  940: 					case EINVAL:
  941: 						err = PHP_ICONV_ERR_ILLEGAL_CHAR;
  942: 						break;
  943: 
  944: 					case EILSEQ:
  945: 						err = PHP_ICONV_ERR_ILLEGAL_SEQ;
  946: 						break;
  947: 
  948: 					case E2BIG:
  949: 						break;
  950: 
  951: 					default:
  952: 						err = PHP_ICONV_ERR_UNKNOWN;
  953: 						break;
  954: 				}
  955: #endif
  956: 				break;
  957: 			}
  958: 		}
  959: 		if (offset >= 0) {
  960: 			if (cnt >= (unsigned int)offset) {
  961: 				if (_php_iconv_memequal(buf, ndl_buf_p, sizeof(buf))) {
  962: 					if (match_ofs == (unsigned int)-1) {
  963: 						match_ofs = cnt;
  964: 					}
  965: 					ndl_buf_p += GENERIC_SUPERSET_NBYTES;
  966: 					ndl_buf_left -= GENERIC_SUPERSET_NBYTES;
  967: 					if (ndl_buf_left == 0) {
  968: 						*pretval = match_ofs;
  969: 						break;
  970: 					}
  971: 				} else {
  972: 					unsigned int i, j, lim;
  973: 
  974: 					i = 0;
  975: 					j = GENERIC_SUPERSET_NBYTES;
  976: 					lim = (unsigned int)(ndl_buf_p - ndl_buf);
  977: 
  978: 					while (j < lim) {
  979: 						if (_php_iconv_memequal(&ndl_buf[j], &ndl_buf[i],
  980: 						           GENERIC_SUPERSET_NBYTES)) {
  981: 							i += GENERIC_SUPERSET_NBYTES;
  982: 						} else {
  983: 							j -= i;
  984: 							i = 0;
  985: 						}
  986: 						j += GENERIC_SUPERSET_NBYTES;
  987: 					}
  988: 
  989: 					if (_php_iconv_memequal(buf, &ndl_buf[i], sizeof(buf))) {
  990: 						match_ofs += (lim - i) / GENERIC_SUPERSET_NBYTES;
  991: 						i += GENERIC_SUPERSET_NBYTES;
  992: 						ndl_buf_p = &ndl_buf[i];
  993: 						ndl_buf_left = ndl_buf_len - i;
  994: 					} else {
  995: 						match_ofs = (unsigned int)-1;
  996: 						ndl_buf_p = ndl_buf;
  997: 						ndl_buf_left = ndl_buf_len;
  998: 					}
  999: 				}
 1000: 			}
 1001: 		} else {
 1002: 			if (_php_iconv_memequal(buf, ndl_buf_p, sizeof(buf))) {
 1003: 				if (match_ofs == (unsigned int)-1) {
 1004: 					match_ofs = cnt;
 1005: 				}
 1006: 				ndl_buf_p += GENERIC_SUPERSET_NBYTES;
 1007: 				ndl_buf_left -= GENERIC_SUPERSET_NBYTES;
 1008: 				if (ndl_buf_left == 0) {
 1009: 					*pretval = match_ofs;
 1010: 					ndl_buf_p = ndl_buf;
 1011: 					ndl_buf_left = ndl_buf_len;
 1012: 					match_ofs = -1;
 1013: 				}
 1014: 			} else {
 1015: 				unsigned int i, j, lim;
 1016: 
 1017: 				i = 0;
 1018: 				j = GENERIC_SUPERSET_NBYTES;
 1019: 				lim = (unsigned int)(ndl_buf_p - ndl_buf);
 1020: 
 1021: 				while (j < lim) {
 1022: 					if (_php_iconv_memequal(&ndl_buf[j], &ndl_buf[i],
 1023: 							   GENERIC_SUPERSET_NBYTES)) {
 1024: 						i += GENERIC_SUPERSET_NBYTES;
 1025: 					} else {
 1026: 						j -= i;
 1027: 						i = 0;
 1028: 					}
 1029: 					j += GENERIC_SUPERSET_NBYTES;
 1030: 				}
 1031: 
 1032: 				if (_php_iconv_memequal(buf, &ndl_buf[i], sizeof(buf))) {
 1033: 					match_ofs += (lim - i) / GENERIC_SUPERSET_NBYTES;
 1034: 					i += GENERIC_SUPERSET_NBYTES;
 1035: 					ndl_buf_p = &ndl_buf[i];
 1036: 					ndl_buf_left = ndl_buf_len - i;
 1037: 				} else {
 1038: 					match_ofs = (unsigned int)-1;
 1039: 					ndl_buf_p = ndl_buf;
 1040: 					ndl_buf_left = ndl_buf_len;
 1041: 				}
 1042: 			}
 1043: 		}
 1044: 	}
 1045: 
 1046: 	if (ndl_buf) {
 1047: 		efree(ndl_buf);
 1048: 	}
 1049: 
 1050: 	iconv_close(cd);
 1051: 
 1052: 	return err;
 1053: }
 1054: /* }}} */
 1055: 
 1056: /* {{{ _php_iconv_mime_encode() */
 1057: static php_iconv_err_t _php_iconv_mime_encode(smart_str *pretval, const char *fname, size_t fname_nbytes, const char *fval, size_t fval_nbytes, unsigned int max_line_len, const char *lfchars, php_iconv_enc_scheme_t enc_scheme, const char *out_charset, const char *enc)
 1058: {
 1059: 	php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS;
 1060: 	iconv_t cd = (iconv_t)(-1), cd_pl = (iconv_t)(-1);
 1061: 	unsigned int char_cnt = 0;
 1062: 	size_t out_charset_len;
 1063: 	size_t lfchars_len;
 1064: 	char *buf = NULL;
 1065: 	char *encoded = NULL;
 1066: 	size_t encoded_len;
 1067: 	const char *in_p;
 1068: 	size_t in_left;
 1069: 	char *out_p;
 1070: 	size_t out_left;
 1071: 	static int qp_table[256] = {
 1072: 		3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x00 */
 1073: 		3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x10 */
 1074: 		3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x20 */
 1075: 		1, 1, 1, 1, 1, 1, 1 ,1, 1, 1, 1, 1, 1, 3, 1, 3, /* 0x30 */
 1076: 		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 */
 1077: 		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, /* 0x50 */
 1078: 		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 */
 1079: 		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, /* 0x70 */
 1080: 		3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x80 */
 1081: 		3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x90 */
 1082: 		3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xA0 */
 1083: 		3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xB0 */
 1084: 		3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xC0 */
 1085: 		3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xD0 */
 1086: 		3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xE0 */
 1087: 		3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3  /* 0xF0 */
 1088: 	};
 1089: 
 1090: 	out_charset_len = strlen(out_charset);
 1091: 	lfchars_len = strlen(lfchars);
 1092: 
 1093: 	if ((fname_nbytes + 2) >= max_line_len
 1094: 		|| (out_charset_len + 12) >= max_line_len) {
 1095: 		/* field name is too long */
 1096: 		err = PHP_ICONV_ERR_TOO_BIG;
 1097: 		goto out;
 1098: 	}
 1099: 
 1100: 	cd_pl = iconv_open(ICONV_ASCII_ENCODING, enc);
 1101: 	if (cd_pl == (iconv_t)(-1)) {
 1102: #if ICONV_SUPPORTS_ERRNO
 1103: 		if (errno == EINVAL) {
 1104: 			err = PHP_ICONV_ERR_WRONG_CHARSET;
 1105: 		} else {
 1106: 			err = PHP_ICONV_ERR_CONVERTER;
 1107: 		}
 1108: #else
 1109: 		err = PHP_ICONV_ERR_UNKNOWN;
 1110: #endif
 1111: 		goto out;
 1112: 	}
 1113: 
 1114: 	cd = iconv_open(out_charset, enc);
 1115: 	if (cd == (iconv_t)(-1)) {
 1116: #if ICONV_SUPPORTS_ERRNO
 1117: 		if (errno == EINVAL) {
 1118: 			err = PHP_ICONV_ERR_WRONG_CHARSET;
 1119: 		} else {
 1120: 			err = PHP_ICONV_ERR_CONVERTER;
 1121: 		}
 1122: #else
 1123: 		err = PHP_ICONV_ERR_UNKNOWN;
 1124: #endif
 1125: 		goto out;
 1126: 	}
 1127: 
 1128: 	buf = safe_emalloc(1, max_line_len, 5);
 1129: 
 1130: 	char_cnt = max_line_len;
 1131: 
 1132: 	_php_iconv_appendl(pretval, fname, fname_nbytes, cd_pl);
 1133: 	char_cnt -= fname_nbytes;
 1134: 	smart_str_appendl(pretval, ": ", sizeof(": ") - 1);
 1135: 	char_cnt -= 2;
 1136: 
 1137: 	in_p = fval;
 1138: 	in_left = fval_nbytes;
 1139: 
 1140: 	do {
 1141: 		size_t prev_in_left;
 1142: 		size_t out_size;
 1143: 
 1144: 		if (char_cnt < (out_charset_len + 12)) {
 1145: 			/* lfchars must be encoded in ASCII here*/
 1146: 			smart_str_appendl(pretval, lfchars, lfchars_len);
 1147: 			smart_str_appendc(pretval, ' ');
 1148: 			char_cnt = max_line_len - 1;
 1149: 		}
 1150: 
 1151: 		smart_str_appendl(pretval, "=?", sizeof("=?") - 1);
 1152: 		char_cnt -= 2;
 1153: 		smart_str_appendl(pretval, out_charset, out_charset_len);
 1154: 		char_cnt -= out_charset_len;
 1155: 		smart_str_appendc(pretval, '?');
 1156: 		char_cnt --;
 1157: 
 1158: 		switch (enc_scheme) {
 1159: 			case PHP_ICONV_ENC_SCHEME_BASE64: {
 1160: 				size_t ini_in_left;
 1161: 				const char *ini_in_p;
 1162: 				size_t out_reserved = 4;
 1163: 				int dummy;
 1164: 
 1165: 				smart_str_appendc(pretval, 'B');
 1166: 				char_cnt--;
 1167: 				smart_str_appendc(pretval, '?');
 1168: 				char_cnt--;
 1169: 
 1170: 				prev_in_left = ini_in_left = in_left;
 1171: 				ini_in_p = in_p;
 1172: 
 1173: 				out_size = (char_cnt - 2) / 4 * 3;
 1174: 
 1175: 				for (;;) {
 1176: 					out_p = buf;
 1177: 
 1178: 					if (out_size <= out_reserved) {
 1179: 						err = PHP_ICONV_ERR_TOO_BIG;
 1180: 						goto out;
 1181: 					}
 1182: 
 1183: 					out_left = out_size - out_reserved;
 1184: 
 1185: 					if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
 1186: #if ICONV_SUPPORTS_ERRNO
 1187: 						switch (errno) {
 1188: 							case EINVAL:
 1189: 								err = PHP_ICONV_ERR_ILLEGAL_CHAR;
 1190: 								goto out;
 1191: 
 1192: 							case EILSEQ:
 1193: 								err = PHP_ICONV_ERR_ILLEGAL_SEQ;
 1194: 								goto out;
 1195: 
 1196: 							case E2BIG:
 1197: 								if (prev_in_left == in_left) {
 1198: 									err = PHP_ICONV_ERR_TOO_BIG;
 1199: 									goto out;
 1200: 								}
 1201: 								break;
 1202: 
 1203: 							default:
 1204: 								err = PHP_ICONV_ERR_UNKNOWN;
 1205: 								goto out;
 1206: 						}
 1207: #else
 1208: 						if (prev_in_left == in_left) {
 1209: 							err = PHP_ICONV_ERR_UNKNOWN;
 1210: 							goto out;
 1211: 						}
 1212: #endif
 1213: 					}
 1214: 
 1215: 					out_left += out_reserved;
 1216: 
 1217: 					if (iconv(cd, NULL, NULL, (char **) &out_p, &out_left) == (size_t)-1) {
 1218: #if ICONV_SUPPORTS_ERRNO
 1219: 						if (errno != E2BIG) {
 1220: 							err = PHP_ICONV_ERR_UNKNOWN;
 1221: 							goto out;
 1222: 						}
 1223: #else
 1224: 						if (out_left != 0) {
 1225: 							err = PHP_ICONV_ERR_UNKNOWN;
 1226: 							goto out;
 1227: 						}
 1228: #endif
 1229: 					} else {
 1230: 						break;
 1231: 					}
 1232: 
 1233: 					if (iconv(cd, NULL, NULL, NULL, NULL) == (size_t)-1) {
 1234: 						err = PHP_ICONV_ERR_UNKNOWN;
 1235: 						goto out;
 1236: 					}
 1237: 
 1238: 					out_reserved += 4;
 1239: 					in_left = ini_in_left;
 1240: 					in_p = ini_in_p;
 1241: 				}
 1242: 
 1243: 				prev_in_left = in_left;
 1244: 
 1245: 				encoded = (char *) php_base64_encode((unsigned char *) buf, (int)(out_size - out_left), &dummy);
 1246: 				encoded_len = (size_t)dummy;
 1247: 
 1248: 				if (char_cnt < encoded_len) {
 1249: 					/* something went wrong! */
 1250: 					err = PHP_ICONV_ERR_UNKNOWN;
 1251: 					goto out;
 1252: 				}
 1253: 
 1254: 				smart_str_appendl(pretval, encoded, encoded_len);
 1255: 				char_cnt -= encoded_len;
 1256: 				smart_str_appendl(pretval, "?=", sizeof("?=") - 1);
 1257: 				char_cnt -= 2;
 1258: 
 1259: 				efree(encoded);
 1260: 				encoded = NULL;
 1261: 			} break; /* case PHP_ICONV_ENC_SCHEME_BASE64: */
 1262: 
 1263: 			case PHP_ICONV_ENC_SCHEME_QPRINT: {
 1264: 				size_t ini_in_left;
 1265: 				const char *ini_in_p;
 1266: 				const unsigned char *p;
 1267: 				size_t nbytes_required;
 1268: 
 1269: 				smart_str_appendc(pretval, 'Q');
 1270: 				char_cnt--;
 1271: 				smart_str_appendc(pretval, '?');
 1272: 				char_cnt--;
 1273: 
 1274: 				prev_in_left = ini_in_left = in_left;
 1275: 				ini_in_p = in_p;
 1276: 
 1277: 				for (out_size = (char_cnt - 2) / 3; out_size > 0;) {
 1278: 					size_t prev_out_left;
 1279: 
 1280: 					nbytes_required = 0;
 1281: 
 1282: 					out_p = buf;
 1283: 					out_left = out_size;
 1284: 
 1285: 					if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
 1286: #if ICONV_SUPPORTS_ERRNO
 1287: 						switch (errno) {
 1288: 							case EINVAL:
 1289: 								err = PHP_ICONV_ERR_ILLEGAL_CHAR;
 1290: 								goto out;
 1291: 
 1292: 							case EILSEQ:
 1293: 								err = PHP_ICONV_ERR_ILLEGAL_SEQ;
 1294: 								goto out;
 1295: 
 1296: 							case E2BIG:
 1297: 								if (prev_in_left == in_left) {
 1298: 									err = PHP_ICONV_ERR_UNKNOWN;
 1299: 									goto out;
 1300: 								}
 1301: 								break;
 1302: 
 1303: 							default:
 1304: 								err = PHP_ICONV_ERR_UNKNOWN;
 1305: 								goto out;
 1306: 						}
 1307: #else
 1308: 						if (prev_in_left == in_left) {
 1309: 							err = PHP_ICONV_ERR_UNKNOWN;
 1310: 							goto out;
 1311: 						}
 1312: #endif
 1313: 					}
 1314: 
 1315: 					prev_out_left = out_left;
 1316: 					if (iconv(cd, NULL, NULL, (char **) &out_p, &out_left) == (size_t)-1) {
 1317: #if ICONV_SUPPORTS_ERRNO
 1318: 						if (errno != E2BIG) {
 1319: 							err = PHP_ICONV_ERR_UNKNOWN;
 1320: 							goto out;
 1321: 						}
 1322: #else
 1323: 						if (out_left == prev_out_left) {
 1324: 							err = PHP_ICONV_ERR_UNKNOWN;
 1325: 							goto out;
 1326: 						}
 1327: #endif
 1328: 					}
 1329: 
 1330: 					for (p = (unsigned char *)buf; p < (unsigned char *)out_p; p++) {
 1331: 						nbytes_required += qp_table[*p];
 1332: 					}
 1333: 
 1334: 					if (nbytes_required <= char_cnt - 2) {
 1335: 						break;
 1336: 					}
 1337: 
 1338: 					out_size -= ((nbytes_required - (char_cnt - 2)) + 1) / 3;
 1339: 					in_left = ini_in_left;
 1340: 					in_p = ini_in_p;
 1341: 				}
 1342: 
 1343: 				for (p = (unsigned char *)buf; p < (unsigned char *)out_p; p++) {
 1344: 					if (qp_table[*p] == 1) {
 1345: 						smart_str_appendc(pretval, *(char *)p);
 1346: 						char_cnt--;
 1347: 					} else {
 1348: 						static char qp_digits[] = "0123456789ABCDEF";
 1349: 						smart_str_appendc(pretval, '=');
 1350: 						smart_str_appendc(pretval, qp_digits[(*p >> 4) & 0x0f]);
 1351: 						smart_str_appendc(pretval, qp_digits[(*p & 0x0f)]);
 1352: 						char_cnt -= 3;
 1353: 					}
 1354: 				}
 1355: 
 1356: 				smart_str_appendl(pretval, "?=", sizeof("?=") - 1);
 1357: 				char_cnt -= 2;
 1358: 
 1359: 				if (iconv(cd, NULL, NULL, NULL, NULL) == (size_t)-1) {
 1360: 					err = PHP_ICONV_ERR_UNKNOWN;
 1361: 					goto out;
 1362: 				}
 1363: 
 1364: 			} break; /* case PHP_ICONV_ENC_SCHEME_QPRINT: */
 1365: 		}
 1366: 	} while (in_left > 0);
 1367: 
 1368: 	smart_str_0(pretval);
 1369: 
 1370: out:
 1371: 	if (cd != (iconv_t)(-1)) {
 1372: 		iconv_close(cd);
 1373: 	}
 1374: 	if (cd_pl != (iconv_t)(-1)) {
 1375: 		iconv_close(cd_pl);
 1376: 	}
 1377: 	if (encoded != NULL) {
 1378: 		efree(encoded);
 1379: 	}
 1380: 	if (buf != NULL) {
 1381: 		efree(buf);
 1382: 	}
 1383: 	return err;
 1384: }
 1385: /* }}} */
 1386: 
 1387: /* {{{ _php_iconv_mime_decode() */
 1388: static php_iconv_err_t _php_iconv_mime_decode(smart_str *pretval, const char *str, size_t str_nbytes, const char *enc, const char **next_pos, int mode)
 1389: {
 1390: 	php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS;
 1391: 
 1392: 	iconv_t cd = (iconv_t)(-1), cd_pl = (iconv_t)(-1);
 1393: 
 1394: 	const char *p1;
 1395: 	size_t str_left;
 1396: 	unsigned int scan_stat = 0;
 1397: 	const char *csname = NULL;
 1398: 	size_t csname_len;
 1399: 	const char *encoded_text = NULL;
 1400: 	size_t encoded_text_len = 0;
 1401: 	const char *encoded_word = NULL;
 1402: 	const char *spaces = NULL;
 1403: 
 1404: 	php_iconv_enc_scheme_t enc_scheme = PHP_ICONV_ENC_SCHEME_BASE64;
 1405: 
 1406: 	if (next_pos != NULL) {
 1407: 		*next_pos = NULL;
 1408: 	}
 1409: 
 1410: 	cd_pl = iconv_open(enc, ICONV_ASCII_ENCODING);
 1411: 
 1412: 	if (cd_pl == (iconv_t)(-1)) {
 1413: #if ICONV_SUPPORTS_ERRNO
 1414: 		if (errno == EINVAL) {
 1415: 			err = PHP_ICONV_ERR_WRONG_CHARSET;
 1416: 		} else {
 1417: 			err = PHP_ICONV_ERR_CONVERTER;
 1418: 		}
 1419: #else
 1420: 		err = PHP_ICONV_ERR_UNKNOWN;
 1421: #endif
 1422: 		goto out;
 1423: 	}
 1424: 
 1425: 	p1 = str;
 1426: 	for (str_left = str_nbytes; str_left > 0; str_left--, p1++) {
 1427: 		int eos = 0;
 1428: 
 1429: 		switch (scan_stat) {
 1430: 			case 0: /* expecting any character */
 1431: 				switch (*p1) {
 1432: 					case '\r': /* part of an EOL sequence? */
 1433: 						scan_stat = 7;
 1434: 						break;
 1435: 
 1436: 					case '\n':
 1437: 						scan_stat = 8;
 1438: 						break;
 1439: 
 1440: 					case '=': /* first letter of an encoded chunk */
 1441: 						encoded_word = p1;
 1442: 						scan_stat = 1;
 1443: 						break;
 1444: 
 1445: 					case ' ': case '\t': /* a chunk of whitespaces */
 1446: 						spaces = p1;
 1447: 						scan_stat = 11;
 1448: 						break;
 1449: 
 1450: 					default: /* first letter of a non-encoded word */
 1451: 						_php_iconv_appendc(pretval, *p1, cd_pl);
 1452: 						encoded_word = NULL;
 1453: 						if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
 1454: 							scan_stat = 12;
 1455: 						}
 1456: 						break;
 1457: 				}
 1458: 				break;
 1459: 
 1460: 			case 1: /* expecting a delimiter */
 1461: 				if (*p1 != '?') {
 1462: 					err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl);
 1463: 					if (err != PHP_ICONV_ERR_SUCCESS) {
 1464: 						goto out;
 1465: 					}
 1466: 					encoded_word = NULL;
 1467: 					if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
 1468: 						scan_stat = 12;
 1469: 					} else {
 1470: 						scan_stat = 0;
 1471: 					}
 1472: 					break;
 1473: 				}
 1474: 				csname = p1 + 1;
 1475: 				scan_stat = 2;
 1476: 				break;
 1477: 
 1478: 			case 2: /* expecting a charset name */
 1479: 				switch (*p1) {
 1480: 					case '?': /* normal delimiter: encoding scheme follows */
 1481: 						scan_stat = 3;
 1482: 						break;
 1483: 
 1484: 					case '*': /* new style delimiter: locale id follows */
 1485: 						scan_stat = 10;
 1486: 						break;
 1487: 				}
 1488: 				if (scan_stat != 2) {
 1489: 					char tmpbuf[80];
 1490: 
 1491: 					if (csname == NULL) {
 1492: 						err = PHP_ICONV_ERR_MALFORMED;
 1493: 						goto out;
 1494: 					}
 1495: 
 1496: 					csname_len = (size_t)(p1 - csname);
 1497: 
 1498: 					if (csname_len > sizeof(tmpbuf) - 1) {
 1499: 						if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
 1500: 							err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl);
 1501: 							if (err != PHP_ICONV_ERR_SUCCESS) {
 1502: 								goto out;
 1503: 							}
 1504: 							encoded_word = NULL;
 1505: 							if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
 1506: 								scan_stat = 12;
 1507: 							} else {
 1508: 								scan_stat = 0;
 1509: 							}
 1510: 							break;
 1511: 						} else {
 1512: 							err = PHP_ICONV_ERR_MALFORMED;
 1513: 							goto out;
 1514: 						}
 1515: 					}
 1516: 
 1517: 					memcpy(tmpbuf, csname, csname_len);
 1518: 					tmpbuf[csname_len] = '\0';
 1519: 
 1520: 					if (cd != (iconv_t)(-1)) {
 1521: 						iconv_close(cd);
 1522: 					}
 1523: 
 1524: 					cd = iconv_open(enc, tmpbuf);
 1525: 
 1526: 					if (cd == (iconv_t)(-1)) {
 1527: 						if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
 1528: 							/* Bad character set, but the user wants us to
 1529: 							 * press on. In this case, we'll just insert the
 1530: 							 * undecoded encoded word, since there isn't really
 1531: 							 * a more sensible behaviour available; the only
 1532: 							 * other options are to swallow the encoded word
 1533: 							 * entirely or decode it with an arbitrarily chosen
 1534: 							 * single byte encoding, both of which seem to have
 1535: 							 * a higher WTF factor than leaving it undecoded.
 1536: 							 *
 1537: 							 * Given this approach, we need to skip ahead to
 1538: 							 * the end of the encoded word. */
 1539: 							int qmarks = 2;
 1540: 							while (qmarks > 0 && str_left > 1) {
 1541: 								if (*(++p1) == '?') {
 1542: 									--qmarks;
 1543: 								}
 1544: 								--str_left;
 1545: 							}
 1546: 
 1547: 							/* Look ahead to check for the terminating = that
 1548: 							 * should be there as well; if it's there, we'll
 1549: 							 * also include that. If it's not, there isn't much
 1550: 							 * we can do at this point. */
 1551: 							if (*(p1 + 1) == '=') {
 1552: 								++p1;
 1553: 								--str_left;
 1554: 							}
 1555: 
 1556: 							err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl);
 1557: 							if (err != PHP_ICONV_ERR_SUCCESS) {
 1558: 								goto out;
 1559: 							}
 1560: 
 1561: 							/* Let's go back and see if there are further
 1562: 							 * encoded words or bare content, and hope they
 1563: 							 * might actually have a valid character set. */
 1564: 							scan_stat = 12;
 1565: 							break;
 1566: 						} else {
 1567: #if ICONV_SUPPORTS_ERRNO
 1568: 							if (errno == EINVAL) {
 1569: 								err = PHP_ICONV_ERR_WRONG_CHARSET;
 1570: 							} else {
 1571: 								err = PHP_ICONV_ERR_CONVERTER;
 1572: 							}
 1573: #else
 1574: 							err = PHP_ICONV_ERR_UNKNOWN;
 1575: #endif
 1576: 							goto out;
 1577: 						}
 1578: 					}
 1579: 				}
 1580: 				break;
 1581: 
 1582: 			case 3: /* expecting a encoding scheme specifier */
 1583: 				switch (*p1) {
 1584: 					case 'b':
 1585: 					case 'B':
 1586: 						enc_scheme = PHP_ICONV_ENC_SCHEME_BASE64;
 1587: 						scan_stat = 4;
 1588: 						break;
 1589: 
 1590: 					case 'q':
 1591: 					case 'Q':
 1592: 						enc_scheme = PHP_ICONV_ENC_SCHEME_QPRINT;
 1593: 						scan_stat = 4;
 1594: 						break;
 1595: 
 1596: 					default:
 1597: 						if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
 1598: 							err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl);
 1599: 							if (err != PHP_ICONV_ERR_SUCCESS) {
 1600: 								goto out;
 1601: 							}
 1602: 							encoded_word = NULL;
 1603: 							if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
 1604: 								scan_stat = 12;
 1605: 							} else {
 1606: 								scan_stat = 0;
 1607: 							}
 1608: 							break;
 1609: 						} else {
 1610: 							err = PHP_ICONV_ERR_MALFORMED;
 1611: 							goto out;
 1612: 						}
 1613: 				}
 1614: 				break;
 1615: 
 1616: 			case 4: /* expecting a delimiter */
 1617: 				if (*p1 != '?') {
 1618: 					if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
 1619: 						/* pass the entire chunk through the converter */
 1620: 						err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl);
 1621: 						if (err != PHP_ICONV_ERR_SUCCESS) {
 1622: 							goto out;
 1623: 						}
 1624: 						encoded_word = NULL;
 1625: 						if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
 1626: 							scan_stat = 12;
 1627: 						} else {
 1628: 							scan_stat = 0;
 1629: 						}
 1630: 						break;
 1631: 					} else {
 1632: 						err = PHP_ICONV_ERR_MALFORMED;
 1633: 						goto out;
 1634: 					}
 1635: 				}
 1636: 				encoded_text = p1 + 1;
 1637: 				scan_stat = 5;
 1638: 				break;
 1639: 
 1640: 			case 5: /* expecting an encoded portion */
 1641: 				if (*p1 == '?') {
 1642: 					encoded_text_len = (size_t)(p1 - encoded_text);
 1643: 					scan_stat = 6;
 1644: 				}
 1645: 				break;
 1646: 
 1647: 			case 7: /* expecting a "\n" character */
 1648: 				if (*p1 == '\n') {
 1649: 					scan_stat = 8;
 1650: 				} else {
 1651: 					/* bare CR */
 1652: 					_php_iconv_appendc(pretval, '\r', cd_pl);
 1653: 					_php_iconv_appendc(pretval, *p1, cd_pl);
 1654: 					scan_stat = 0;
 1655: 				}
 1656: 				break;
 1657: 
 1658: 			case 8: /* checking whether the following line is part of a
 1659: 					   folded header */
 1660: 				if (*p1 != ' ' && *p1 != '\t') {
 1661: 					--p1;
 1662: 					str_left = 1; /* quit_loop */
 1663: 					break;
 1664: 				}
 1665: 				if (encoded_word == NULL) {
 1666: 					_php_iconv_appendc(pretval, ' ', cd_pl);
 1667: 				}
 1668: 				spaces = NULL;
 1669: 				scan_stat = 11;
 1670: 				break;
 1671: 
 1672: 			case 6: /* expecting a End-Of-Chunk character "=" */
 1673: 				if (*p1 != '=') {
 1674: 					if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
 1675: 						/* pass the entire chunk through the converter */
 1676: 						err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl);
 1677: 						if (err != PHP_ICONV_ERR_SUCCESS) {
 1678: 							goto out;
 1679: 						}
 1680: 						encoded_word = NULL;
 1681: 						if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
 1682: 							scan_stat = 12;
 1683: 						} else {
 1684: 							scan_stat = 0;
 1685: 						}
 1686: 						break;
 1687: 					} else {
 1688: 						err = PHP_ICONV_ERR_MALFORMED;
 1689: 						goto out;
 1690: 					}
 1691: 				}
 1692: 				scan_stat = 9;
 1693: 				if (str_left == 1) {
 1694: 					eos = 1;
 1695: 				} else {
 1696: 					break;
 1697: 				}
 1698: 
 1699: 			case 9: /* choice point, seeing what to do next.*/
 1700: 				switch (*p1) {
 1701: 					default:
 1702: 						/* Handle non-RFC-compliant formats
 1703: 						 *
 1704: 						 * RFC2047 requires the character that comes right
 1705: 						 * after an encoded word (chunk) to be a whitespace,
 1706: 						 * while there are lots of broken implementations that
 1707: 						 * generate such malformed headers that don't fulfill
 1708: 						 * that requirement.
 1709: 						 */
 1710: 						if (!eos) {
 1711: 							if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
 1712: 								/* pass the entire chunk through the converter */
 1713: 								err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl);
 1714: 								if (err != PHP_ICONV_ERR_SUCCESS) {
 1715: 									goto out;
 1716: 								}
 1717: 								scan_stat = 12;
 1718: 								break;
 1719: 							}
 1720: 						}
 1721: 						/* break is omitted intentionally */
 1722: 
 1723: 					case '\r': case '\n': case ' ': case '\t': {
 1724: 						char *decoded_text;
 1725: 						size_t decoded_text_len;
 1726: 						int dummy;
 1727: 
 1728: 						switch (enc_scheme) {
 1729: 							case PHP_ICONV_ENC_SCHEME_BASE64:
 1730: 								decoded_text = (char *)php_base64_decode((unsigned char*)encoded_text, (int)encoded_text_len, &dummy);
 1731: 								decoded_text_len = (size_t)dummy;
 1732: 								break;
 1733: 
 1734: 							case PHP_ICONV_ENC_SCHEME_QPRINT:
 1735: 								decoded_text = (char *)php_quot_print_decode((unsigned char*)encoded_text, (int)encoded_text_len, &decoded_text_len, 1);
 1736: 								break;
 1737: 							default:
 1738: 								decoded_text = NULL;
 1739: 								break;
 1740: 						}
 1741: 
 1742: 						if (decoded_text == NULL) {
 1743: 							if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
 1744: 								/* pass the entire chunk through the converter */
 1745: 								err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl);
 1746: 								if (err != PHP_ICONV_ERR_SUCCESS) {
 1747: 									goto out;
 1748: 								}
 1749: 								encoded_word = NULL;
 1750: 								if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
 1751: 									scan_stat = 12;
 1752: 								} else {
 1753: 									scan_stat = 0;
 1754: 								}
 1755: 								break;
 1756: 							} else {
 1757: 								err = PHP_ICONV_ERR_UNKNOWN;
 1758: 								goto out;
 1759: 							}
 1760: 						}
 1761: 
 1762: 						err = _php_iconv_appendl(pretval, decoded_text, decoded_text_len, cd);
 1763: 						efree(decoded_text);
 1764: 
 1765: 						if (err != PHP_ICONV_ERR_SUCCESS) {
 1766: 							if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
 1767: 								/* pass the entire chunk through the converter */
 1768: 								err = _php_iconv_appendl(pretval, encoded_word, (size_t)(p1 - encoded_word), cd_pl);
 1769: 								encoded_word = NULL;
 1770: 								if (err != PHP_ICONV_ERR_SUCCESS) {
 1771: 									break;
 1772: 								}
 1773: 							} else {
 1774: 								goto out;
 1775: 							}
 1776: 						}
 1777: 
 1778: 						if (eos) { /* reached end-of-string. done. */
 1779: 							scan_stat = 0;
 1780: 							break;
 1781: 						}
 1782: 
 1783: 						switch (*p1) {
 1784: 							case '\r': /* part of an EOL sequence? */
 1785: 								scan_stat = 7;
 1786: 								break;
 1787: 
 1788: 							case '\n':
 1789: 								scan_stat = 8;
 1790: 								break;
 1791: 
 1792: 							case '=': /* first letter of an encoded chunk */
 1793: 								scan_stat = 1;
 1794: 								break;
 1795: 
 1796: 							case ' ': case '\t': /* medial whitespaces */
 1797: 								spaces = p1;
 1798: 								scan_stat = 11;
 1799: 								break;
 1800: 
 1801: 							default: /* first letter of a non-encoded word */
 1802: 								_php_iconv_appendc(pretval, *p1, cd_pl);
 1803: 								scan_stat = 12;
 1804: 								break;
 1805: 						}
 1806: 					} break;
 1807: 				}
 1808: 				break;
 1809: 
 1810: 			case 10: /* expects a language specifier. dismiss it for now */
 1811: 				if (*p1 == '?') {
 1812: 					scan_stat = 3;
 1813: 				}
 1814: 				break;
 1815: 
 1816: 			case 11: /* expecting a chunk of whitespaces */
 1817: 				switch (*p1) {
 1818: 					case '\r': /* part of an EOL sequence? */
 1819: 						scan_stat = 7;
 1820: 						break;
 1821: 
 1822: 					case '\n':
 1823: 						scan_stat = 8;
 1824: 						break;
 1825: 
 1826: 					case '=': /* first letter of an encoded chunk */
 1827: 						if (spaces != NULL && encoded_word == NULL) {
 1828: 							_php_iconv_appendl(pretval, spaces, (size_t)(p1 - spaces), cd_pl);
 1829: 							spaces = NULL;
 1830: 						}
 1831: 						encoded_word = p1;
 1832: 						scan_stat = 1;
 1833: 						break;
 1834: 
 1835: 					case ' ': case '\t':
 1836: 						break;
 1837: 
 1838: 					default: /* first letter of a non-encoded word */
 1839: 						if (spaces != NULL) {
 1840: 							_php_iconv_appendl(pretval, spaces, (size_t)(p1 - spaces), cd_pl);
 1841: 							spaces = NULL;
 1842: 						}
 1843: 						_php_iconv_appendc(pretval, *p1, cd_pl);
 1844: 						encoded_word = NULL;
 1845: 						if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
 1846: 							scan_stat = 12;
 1847: 						} else {
 1848: 							scan_stat = 0;
 1849: 						}
 1850: 						break;
 1851: 				}
 1852: 				break;
 1853: 
 1854: 			case 12: /* expecting a non-encoded word */
 1855: 				switch (*p1) {
 1856: 					case '\r': /* part of an EOL sequence? */
 1857: 						scan_stat = 7;
 1858: 						break;
 1859: 
 1860: 					case '\n':
 1861: 						scan_stat = 8;
 1862: 						break;
 1863: 
 1864: 					case ' ': case '\t':
 1865: 						spaces = p1;
 1866: 						scan_stat = 11;
 1867: 						break;
 1868: 
 1869: 					case '=': /* first letter of an encoded chunk */
 1870: 						if (!(mode & PHP_ICONV_MIME_DECODE_STRICT)) {
 1871: 							encoded_word = p1;
 1872: 							scan_stat = 1;
 1873: 							break;
 1874: 						}
 1875: 						/* break is omitted intentionally */
 1876: 
 1877: 					default:
 1878: 						_php_iconv_appendc(pretval, *p1, cd_pl);
 1879: 						break;
 1880: 				}
 1881: 				break;
 1882: 		}
 1883: 	}
 1884: 	switch (scan_stat) {
 1885: 		case 0: case 8: case 11: case 12:
 1886: 			break;
 1887: 		default:
 1888: 			if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
 1889: 				if (scan_stat == 1) {
 1890: 					_php_iconv_appendc(pretval, '=', cd_pl);
 1891: 				}
 1892: 				err = PHP_ICONV_ERR_SUCCESS;
 1893: 			} else {
 1894: 				err = PHP_ICONV_ERR_MALFORMED;
 1895: 				goto out;
 1896: 			}
 1897: 	}
 1898: 
 1899: 	if (next_pos != NULL) {
 1900: 		*next_pos = p1;
 1901: 	}
 1902: 
 1903: 	smart_str_0(pretval);
 1904: out:
 1905: 	if (cd != (iconv_t)(-1)) {
 1906: 		iconv_close(cd);
 1907: 	}
 1908: 	if (cd_pl != (iconv_t)(-1)) {
 1909: 		iconv_close(cd_pl);
 1910: 	}
 1911: 	return err;
 1912: }
 1913: /* }}} */
 1914: 
 1915: /* {{{ php_iconv_show_error() */
 1916: static void _php_iconv_show_error(php_iconv_err_t err, const char *out_charset, const char *in_charset TSRMLS_DC)
 1917: {
 1918: 	switch (err) {
 1919: 		case PHP_ICONV_ERR_SUCCESS:
 1920: 			break;
 1921: 
 1922: 		case PHP_ICONV_ERR_CONVERTER:
 1923: 			php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot open converter");
 1924: 			break;
 1925: 
 1926: 		case PHP_ICONV_ERR_WRONG_CHARSET:
 1927: 			php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong charset, conversion from `%s' to `%s' is not allowed",
 1928: 			          in_charset, out_charset);
 1929: 			break;
 1930: 
 1931: 		case PHP_ICONV_ERR_ILLEGAL_CHAR:
 1932: 			php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected an incomplete multibyte character in input string");
 1933: 			break;
 1934: 
 1935: 		case PHP_ICONV_ERR_ILLEGAL_SEQ:
 1936: 			php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected an illegal character in input string");
 1937: 			break;
 1938: 
 1939: 		case PHP_ICONV_ERR_TOO_BIG:
 1940: 			/* should not happen */
 1941: 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Buffer length exceeded");
 1942: 			break;
 1943: 
 1944: 		case PHP_ICONV_ERR_MALFORMED:
 1945: 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Malformed string");
 1946: 			break;
 1947: 
 1948: 		default:
 1949: 			/* other error */
 1950: 			php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unknown error (%d)", errno);
 1951: 			break;
 1952: 	}
 1953: }
 1954: /* }}} */
 1955: 
 1956: /* {{{ proto int iconv_strlen(string str [, string charset])
 1957:    Returns the character count of str */
 1958: PHP_FUNCTION(iconv_strlen)
 1959: {
 1960: 	char *charset = ICONVG(internal_encoding);
 1961: 	int charset_len = 0;
 1962: 	char *str;
 1963: 	int str_len;
 1964: 
 1965: 	php_iconv_err_t err;
 1966: 
 1967: 	unsigned int retval;
 1968: 
 1969: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s",
 1970: 		&str, &str_len, &charset, &charset_len) == FAILURE) {
 1971: 		RETURN_FALSE;
 1972: 	}
 1973: 
 1974: 	if (charset_len >= ICONV_CSNMAXLEN) {
 1975: 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
 1976: 		RETURN_FALSE;
 1977: 	}
 1978: 
 1979: 	err = _php_iconv_strlen(&retval, str, str_len, charset);
 1980: 	_php_iconv_show_error(err, GENERIC_SUPERSET_NAME, charset TSRMLS_CC);
 1981: 	if (err == PHP_ICONV_ERR_SUCCESS) {
 1982: 		RETVAL_LONG(retval);
 1983: 	} else {
 1984: 		RETVAL_FALSE;
 1985: 	}
 1986: }
 1987: /* }}} */
 1988: 
 1989: /* {{{ proto string iconv_substr(string str, int offset, [int length, string charset])
 1990:    Returns specified part of a string */
 1991: PHP_FUNCTION(iconv_substr)
 1992: {
 1993: 	char *charset = ICONVG(internal_encoding);
 1994: 	int charset_len = 0;
 1995: 	char *str;
 1996: 	int str_len;
 1997: 	long offset, length = 0;
 1998: 
 1999: 	php_iconv_err_t err;
 2000: 
 2001: 	smart_str retval = {0};
 2002: 
 2003: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|ls",
 2004: 		&str, &str_len, &offset, &length,
 2005: 		&charset, &charset_len) == FAILURE) {
 2006: 		RETURN_FALSE;
 2007: 	}
 2008: 
 2009: 	if (charset_len >= ICONV_CSNMAXLEN) {
 2010: 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
 2011: 		RETURN_FALSE;
 2012: 	}
 2013: 
 2014: 	if (ZEND_NUM_ARGS() < 3) {
 2015: 		length = str_len;
 2016: 	}
 2017: 
 2018: 	err = _php_iconv_substr(&retval, str, str_len, offset, length, charset);
 2019: 	_php_iconv_show_error(err, GENERIC_SUPERSET_NAME, charset TSRMLS_CC);
 2020: 
 2021: 	if (err == PHP_ICONV_ERR_SUCCESS && str != NULL && retval.c != NULL) {
 2022: 		RETURN_STRINGL(retval.c, retval.len, 0);
 2023: 	}
 2024: 	smart_str_free(&retval);
 2025: 	RETURN_FALSE;
 2026: }
 2027: /* }}} */
 2028: 
 2029: /* {{{ proto int iconv_strpos(string haystack, string needle [, int offset [, string charset]])
 2030:    Finds position of first occurrence of needle within part of haystack beginning with offset */
 2031: PHP_FUNCTION(iconv_strpos)
 2032: {
 2033: 	char *charset = ICONVG(internal_encoding);
 2034: 	int charset_len = 0;
 2035: 	char *haystk;
 2036: 	int haystk_len;
 2037: 	char *ndl;
 2038: 	int ndl_len;
 2039: 	long offset = 0;
 2040: 
 2041: 	php_iconv_err_t err;
 2042: 
 2043: 	unsigned int retval;
 2044: 
 2045: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ls",
 2046: 		&haystk, &haystk_len, &ndl, &ndl_len,
 2047: 		&offset, &charset, &charset_len) == FAILURE) {
 2048: 		RETURN_FALSE;
 2049: 	}
 2050: 
 2051: 	if (charset_len >= ICONV_CSNMAXLEN) {
 2052: 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
 2053: 		RETURN_FALSE;
 2054: 	}
 2055: 
 2056: 	if (offset < 0) {
 2057: 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset not contained in string.");
 2058: 		RETURN_FALSE;
 2059: 	}
 2060: 
 2061: 	if (ndl_len < 1) {
 2062: 		RETURN_FALSE;
 2063: 	}
 2064: 
 2065: 	err = _php_iconv_strpos(&retval, haystk, haystk_len, ndl, ndl_len,
 2066: 	                        offset, charset);
 2067: 	_php_iconv_show_error(err, GENERIC_SUPERSET_NAME, charset TSRMLS_CC);
 2068: 
 2069: 	if (err == PHP_ICONV_ERR_SUCCESS && retval != (unsigned int)-1) {
 2070: 		RETVAL_LONG((long)retval);
 2071: 	} else {
 2072: 		RETVAL_FALSE;
 2073: 	}
 2074: }
 2075: /* }}} */
 2076: 
 2077: /* {{{ proto int iconv_strrpos(string haystack, string needle [, string charset])
 2078:    Finds position of last occurrence of needle within part of haystack beginning with offset */
 2079: PHP_FUNCTION(iconv_strrpos)
 2080: {
 2081: 	char *charset = ICONVG(internal_encoding);
 2082: 	int charset_len = 0;
 2083: 	char *haystk;
 2084: 	int haystk_len;
 2085: 	char *ndl;
 2086: 	int ndl_len;
 2087: 
 2088: 	php_iconv_err_t err;
 2089: 
 2090: 	unsigned int retval;
 2091: 
 2092: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s",
 2093: 		&haystk, &haystk_len, &ndl, &ndl_len,
 2094: 		&charset, &charset_len) == FAILURE) {
 2095: 		RETURN_FALSE;
 2096: 	}
 2097: 
 2098: 	if (ndl_len < 1) {
 2099: 		RETURN_FALSE;
 2100: 	}
 2101: 
 2102: 	if (charset_len >= ICONV_CSNMAXLEN) {
 2103: 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
 2104: 		RETURN_FALSE;
 2105: 	}
 2106: 
 2107: 	err = _php_iconv_strpos(&retval, haystk, haystk_len, ndl, ndl_len,
 2108: 	                        -1, charset);
 2109: 	_php_iconv_show_error(err, GENERIC_SUPERSET_NAME, charset TSRMLS_CC);
 2110: 
 2111: 	if (err == PHP_ICONV_ERR_SUCCESS && retval != (unsigned int)-1) {
 2112: 		RETVAL_LONG((long)retval);
 2113: 	} else {
 2114: 		RETVAL_FALSE;
 2115: 	}
 2116: }
 2117: /* }}} */
 2118: 
 2119: /* {{{ proto string iconv_mime_encode(string field_name, string field_value [, array preference])
 2120:    Composes a mime header field with field_name and field_value in a specified scheme */
 2121: PHP_FUNCTION(iconv_mime_encode)
 2122: {
 2123: 	const char *field_name = NULL;
 2124: 	int field_name_len;
 2125: 	const char *field_value = NULL;
 2126: 	int field_value_len;
 2127: 	zval *pref = NULL;
 2128: 	zval tmp_zv, *tmp_zv_p = NULL;
 2129: 	smart_str retval = {0};
 2130: 	php_iconv_err_t err;
 2131: 
 2132: 	const char *in_charset = ICONVG(internal_encoding);
 2133: 	const char *out_charset = in_charset;
 2134: 	long line_len = 76;
 2135: 	const char *lfchars = "\r\n";
 2136: 	php_iconv_enc_scheme_t scheme_id = PHP_ICONV_ENC_SCHEME_BASE64;
 2137: 
 2138: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a",
 2139: 		&field_name, &field_name_len, &field_value, &field_value_len,
 2140: 		&pref) == FAILURE) {
 2141: 
 2142: 		RETURN_FALSE;
 2143: 	}
 2144: 
 2145: 	if (pref != NULL) {
 2146: 		zval **ppval;
 2147: 
 2148: 		if (zend_hash_find(Z_ARRVAL_P(pref), "scheme", sizeof("scheme"), (void **)&ppval) == SUCCESS) {
 2149: 			if (Z_TYPE_PP(ppval) == IS_STRING && Z_STRLEN_PP(ppval) > 0) {
 2150: 				switch (Z_STRVAL_PP(ppval)[0]) {
 2151: 					case 'B': case 'b':
 2152: 						scheme_id = PHP_ICONV_ENC_SCHEME_BASE64;
 2153: 						break;
 2154: 
 2155: 					case 'Q': case 'q':
 2156: 						scheme_id = PHP_ICONV_ENC_SCHEME_QPRINT;
 2157: 						break;
 2158: 				}
 2159: 			}
 2160: 		}
 2161: 
 2162: 		if (zend_hash_find(Z_ARRVAL_P(pref), "input-charset", sizeof("input-charset"), (void **)&ppval) == SUCCESS) {
 2163: 			if (Z_STRLEN_PP(ppval) >= ICONV_CSNMAXLEN) {
 2164: 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
 2165: 				RETURN_FALSE;
 2166: 			}
 2167: 
 2168: 			if (Z_TYPE_PP(ppval) == IS_STRING && Z_STRLEN_PP(ppval) > 0) {
 2169: 				in_charset = Z_STRVAL_PP(ppval);
 2170: 			}
 2171: 		}
 2172: 
 2173: 
 2174: 		if (zend_hash_find(Z_ARRVAL_P(pref), "output-charset", sizeof("output-charset"), (void **)&ppval) == SUCCESS) {
 2175: 			if (Z_STRLEN_PP(ppval) >= ICONV_CSNMAXLEN) {
 2176: 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
 2177: 				RETURN_FALSE;
 2178: 			}
 2179: 
 2180: 			if (Z_TYPE_PP(ppval) == IS_STRING && Z_STRLEN_PP(ppval) > 0) {
 2181: 				out_charset = Z_STRVAL_PP(ppval);
 2182: 			}
 2183: 		}
 2184: 
 2185: 		if (zend_hash_find(Z_ARRVAL_P(pref), "line-length", sizeof("line-length"), (void **)&ppval) == SUCCESS) {
 2186: 			zval val, *pval = *ppval;
 2187: 
 2188: 			if (Z_TYPE_P(pval) != IS_LONG) {
 2189: 				val = *pval;
 2190: 				zval_copy_ctor(&val);
 2191: 				convert_to_long(&val);
 2192: 				pval = &val;
 2193: 			}
 2194: 
 2195: 			line_len = Z_LVAL_P(pval);
 2196: 
 2197: 			if (pval == &val) {
 2198: 				zval_dtor(&val);
 2199: 			}
 2200: 		}
 2201: 
 2202: 		if (zend_hash_find(Z_ARRVAL_P(pref), "line-break-chars", sizeof("line-break-chars"), (void **)&ppval) == SUCCESS) {
 2203: 			if (Z_TYPE_PP(ppval) != IS_STRING) {
 2204: 				tmp_zv = **ppval;
 2205: 				zval_copy_ctor(&tmp_zv);
 2206: 				convert_to_string(&tmp_zv);
 2207: 
 2208: 				lfchars = Z_STRVAL(tmp_zv);
 2209: 
 2210: 				tmp_zv_p = &tmp_zv;
 2211: 			} else {
 2212: 				lfchars = Z_STRVAL_PP(ppval);
 2213: 			}
 2214: 		}
 2215: 	}
 2216: 
 2217: 	err = _php_iconv_mime_encode(&retval, field_name, field_name_len,
 2218: 		field_value, field_value_len, line_len, lfchars, scheme_id,
 2219: 		out_charset, in_charset);
 2220: 	_php_iconv_show_error(err, out_charset, in_charset TSRMLS_CC);
 2221: 
 2222: 	if (err == PHP_ICONV_ERR_SUCCESS) {
 2223: 		if (retval.c != NULL) {
 2224: 			RETVAL_STRINGL(retval.c, retval.len, 0);
 2225: 		} else {
 2226: 			RETVAL_EMPTY_STRING();
 2227: 		}
 2228: 	} else {
 2229: 		smart_str_free(&retval);
 2230: 		RETVAL_FALSE;
 2231: 	}
 2232: 
 2233: 	if (tmp_zv_p != NULL) {
 2234: 		zval_dtor(tmp_zv_p);
 2235: 	}
 2236: }
 2237: /* }}} */
 2238: 
 2239: /* {{{ proto string iconv_mime_decode(string encoded_string [, int mode, string charset])
 2240:    Decodes a mime header field */
 2241: PHP_FUNCTION(iconv_mime_decode)
 2242: {
 2243: 	char *encoded_str;
 2244: 	int encoded_str_len;
 2245: 	char *charset = ICONVG(internal_encoding);
 2246: 	int charset_len = 0;
 2247: 	long mode = 0;
 2248: 
 2249: 	smart_str retval = {0};
 2250: 
 2251: 	php_iconv_err_t err;
 2252: 
 2253: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls",
 2254: 		&encoded_str, &encoded_str_len, &mode, &charset, &charset_len) == FAILURE) {
 2255: 
 2256: 		RETURN_FALSE;
 2257: 	}
 2258: 
 2259: 	if (charset_len >= ICONV_CSNMAXLEN) {
 2260: 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
 2261: 		RETURN_FALSE;
 2262: 	}
 2263: 
 2264: 	err = _php_iconv_mime_decode(&retval, encoded_str, encoded_str_len, charset, NULL, mode);
 2265: 	_php_iconv_show_error(err, charset, "???" TSRMLS_CC);
 2266: 
 2267: 	if (err == PHP_ICONV_ERR_SUCCESS) {
 2268: 		if (retval.c != NULL) {
 2269: 			RETVAL_STRINGL(retval.c, retval.len, 0);
 2270: 		} else {
 2271: 			RETVAL_EMPTY_STRING();
 2272: 		}
 2273: 	} else {
 2274: 		smart_str_free(&retval);
 2275: 		RETVAL_FALSE;
 2276: 	}
 2277: }
 2278: /* }}} */
 2279: 
 2280: /* {{{ proto array iconv_mime_decode_headers(string headers [, int mode, string charset])
 2281:    Decodes multiple mime header fields */
 2282: PHP_FUNCTION(iconv_mime_decode_headers)
 2283: {
 2284: 	const char *encoded_str;
 2285: 	int encoded_str_len;
 2286: 	char *charset = ICONVG(internal_encoding);
 2287: 	int charset_len = 0;
 2288: 	long mode = 0;
 2289: 
 2290: 	php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS;
 2291: 
 2292: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls",
 2293: 		&encoded_str, &encoded_str_len, &mode, &charset, &charset_len) == FAILURE) {
 2294: 
 2295: 		RETURN_FALSE;
 2296: 	}
 2297: 
 2298: 	if (charset_len >= ICONV_CSNMAXLEN) {
 2299: 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
 2300: 		RETURN_FALSE;
 2301: 	}
 2302: 
 2303: 	array_init(return_value);
 2304: 
 2305: 	while (encoded_str_len > 0) {
 2306: 		smart_str decoded_header = {0};
 2307: 		char *header_name = NULL;
 2308: 		size_t header_name_len = 0;
 2309: 		char *header_value = NULL;
 2310: 		size_t header_value_len = 0;
 2311: 		char *p, *limit;
 2312: 		const char *next_pos;
 2313: 
 2314: 		if (PHP_ICONV_ERR_SUCCESS != (err = _php_iconv_mime_decode(&decoded_header, encoded_str, encoded_str_len, charset, &next_pos, mode))) {
 2315: 			smart_str_free(&decoded_header);
 2316: 			break;
 2317: 		}
 2318: 
 2319: 		if (decoded_header.c == NULL) {
 2320: 			break;
 2321: 		}
 2322: 
 2323: 		limit = decoded_header.c + decoded_header.len;
 2324: 		for (p = decoded_header.c; p < limit; p++) {
 2325: 			if (*p == ':') {
 2326: 				*p = '\0';
 2327: 				header_name = decoded_header.c;
 2328: 				header_name_len = (p - decoded_header.c) + 1;
 2329: 
 2330: 				while (++p < limit) {
 2331: 					if (*p != ' ' && *p != '\t') {
 2332: 						break;
 2333: 					}
 2334: 				}
 2335: 
 2336: 				header_value = p;
 2337: 				header_value_len = limit - p;
 2338: 
 2339: 				break;
 2340: 			}
 2341: 		}
 2342: 
 2343: 		if (header_name != NULL) {
 2344: 			zval **elem, *new_elem;
 2345: 
 2346: 			if (zend_hash_find(Z_ARRVAL_P(return_value), header_name, header_name_len, (void **)&elem) == SUCCESS) {
 2347: 				if (Z_TYPE_PP(elem) != IS_ARRAY) {
 2348: 					MAKE_STD_ZVAL(new_elem);
 2349: 					array_init(new_elem);
 2350: 
 2351: 					Z_ADDREF_PP(elem);
 2352: 					add_next_index_zval(new_elem, *elem);
 2353: 
 2354: 					zend_hash_update(Z_ARRVAL_P(return_value), header_name, header_name_len, (void *)&new_elem, sizeof(new_elem), NULL);
 2355: 
 2356: 					elem = &new_elem;
 2357: 				}
 2358: 				add_next_index_stringl(*elem, header_value, header_value_len, 1);
 2359: 			} else {
 2360: 				add_assoc_stringl_ex(return_value, header_name, header_name_len, header_value, header_value_len, 1);
 2361: 			}
 2362: 		}
 2363: 		encoded_str_len -= next_pos - encoded_str;
 2364: 		encoded_str = next_pos;
 2365: 
 2366: 		smart_str_free(&decoded_header);
 2367: 	}
 2368: 
 2369: 	if (err != PHP_ICONV_ERR_SUCCESS) {
 2370: 		_php_iconv_show_error(err, charset, "???" TSRMLS_CC);
 2371: 		zval_dtor(return_value);
 2372: 		RETVAL_FALSE;
 2373: 	}
 2374: }
 2375: /* }}} */
 2376: 
 2377: /* {{{ proto string iconv(string in_charset, string out_charset, string str)
 2378:    Returns str converted to the out_charset character set */
 2379: PHP_NAMED_FUNCTION(php_if_iconv)
 2380: {
 2381: 	char *in_charset, *out_charset, *in_buffer, *out_buffer;
 2382: 	size_t out_len;
 2383: 	int in_charset_len = 0, out_charset_len = 0, in_buffer_len;
 2384: 	php_iconv_err_t err;
 2385: 
 2386: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss",
 2387: 		&in_charset, &in_charset_len, &out_charset, &out_charset_len, &in_buffer, &in_buffer_len) == FAILURE)
 2388: 		return;
 2389: 
 2390: 	if (in_charset_len >= ICONV_CSNMAXLEN || out_charset_len >= ICONV_CSNMAXLEN) {
 2391: 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
 2392: 		RETURN_FALSE;
 2393: 	}
 2394: 
 2395: 	err = php_iconv_string(in_buffer, (size_t)in_buffer_len,
 2396: 		&out_buffer, &out_len, out_charset, in_charset);
 2397: 	_php_iconv_show_error(err, out_charset, in_charset TSRMLS_CC);
 2398: 	if (err == PHP_ICONV_ERR_SUCCESS && out_buffer != NULL) {
 2399: 		RETVAL_STRINGL(out_buffer, out_len, 0);
 2400: 	} else {
 2401: 		if (out_buffer != NULL) {
 2402: 			efree(out_buffer);
 2403: 		}
 2404: 		RETURN_FALSE;
 2405: 	}
 2406: }
 2407: /* }}} */
 2408: 
 2409: /* {{{ proto bool iconv_set_encoding(string type, string charset)
 2410:    Sets internal encoding and output encoding for ob_iconv_handler() */
 2411: PHP_FUNCTION(iconv_set_encoding)
 2412: {
 2413: 	char *type, *charset;
 2414: 	int type_len, charset_len =0, retval;
 2415: 
 2416: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &type, &type_len, &charset, &charset_len) == FAILURE)
 2417: 		return;
 2418: 
 2419: 	if (charset_len >= ICONV_CSNMAXLEN) {
 2420: 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
 2421: 		RETURN_FALSE;
 2422: 	}
 2423: 
 2424: 	if(!strcasecmp("input_encoding", type)) {
 2425: 		retval = zend_alter_ini_entry("iconv.input_encoding", sizeof("iconv.input_encoding"), charset, charset_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
 2426: 	} else if(!strcasecmp("output_encoding", type)) {
 2427: 		retval = zend_alter_ini_entry("iconv.output_encoding", sizeof("iconv.output_encoding"), charset, charset_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
 2428: 	} else if(!strcasecmp("internal_encoding", type)) {
 2429: 		retval = zend_alter_ini_entry("iconv.internal_encoding", sizeof("iconv.internal_encoding"), charset, charset_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
 2430: 	} else {
 2431: 		RETURN_FALSE;
 2432: 	}
 2433: 
 2434: 	if (retval == SUCCESS) {
 2435: 		RETURN_TRUE;
 2436: 	} else {
 2437: 		RETURN_FALSE;
 2438: 	}
 2439: }
 2440: /* }}} */
 2441: 
 2442: /* {{{ proto mixed iconv_get_encoding([string type])
 2443:    Get internal encoding and output encoding for ob_iconv_handler() */
 2444: PHP_FUNCTION(iconv_get_encoding)
 2445: {
 2446: 	char *type = "all";
 2447: 	int type_len = sizeof("all")-1;
 2448: 
 2449: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &type, &type_len) == FAILURE)
 2450: 		return;
 2451: 
 2452: 	if (!strcasecmp("all", type)) {
 2453: 		array_init(return_value);
 2454: 		add_assoc_string(return_value, "input_encoding",    ICONVG(input_encoding), 1);
 2455: 		add_assoc_string(return_value, "output_encoding",   ICONVG(output_encoding), 1);
 2456: 		add_assoc_string(return_value, "internal_encoding", ICONVG(internal_encoding), 1);
 2457: 	} else if (!strcasecmp("input_encoding", type)) {
 2458: 		RETVAL_STRING(ICONVG(input_encoding), 1);
 2459: 	} else if (!strcasecmp("output_encoding", type)) {
 2460: 		RETVAL_STRING(ICONVG(output_encoding), 1);
 2461: 	} else if (!strcasecmp("internal_encoding", type)) {
 2462: 		RETVAL_STRING(ICONVG(internal_encoding), 1);
 2463: 	} else {
 2464: 		RETURN_FALSE;
 2465: 	}
 2466: 
 2467: }
 2468: /* }}} */
 2469: 
 2470: /* {{{ iconv stream filter */
 2471: typedef struct _php_iconv_stream_filter {
 2472: 	iconv_t cd;
 2473: 	int persistent;
 2474: 	char *to_charset;
 2475: 	size_t to_charset_len;
 2476: 	char *from_charset;
 2477: 	size_t from_charset_len;
 2478: 	char stub[128];
 2479: 	size_t stub_len;
 2480: } php_iconv_stream_filter;
 2481: /* }}} iconv stream filter */
 2482: 
 2483: /* {{{ php_iconv_stream_filter_dtor */
 2484: static void php_iconv_stream_filter_dtor(php_iconv_stream_filter *self)
 2485: {
 2486: 	iconv_close(self->cd);
 2487: 	pefree(self->to_charset, self->persistent);
 2488: 	pefree(self->from_charset, self->persistent);
 2489: }
 2490: /* }}} */
 2491: 
 2492: /* {{{ php_iconv_stream_filter_ctor() */
 2493: static php_iconv_err_t php_iconv_stream_filter_ctor(php_iconv_stream_filter *self,
 2494: 		const char *to_charset, size_t to_charset_len,
 2495: 		const char *from_charset, size_t from_charset_len, int persistent)
 2496: {
 2497: 	if (NULL == (self->to_charset = pemalloc(to_charset_len + 1, persistent))) {
 2498: 		return PHP_ICONV_ERR_ALLOC;
 2499: 	}
 2500: 	self->to_charset_len = to_charset_len;
 2501: 	if (NULL == (self->from_charset = pemalloc(from_charset_len + 1, persistent))) {
 2502: 		pefree(self->to_charset, persistent);
 2503: 		return PHP_ICONV_ERR_ALLOC;
 2504: 	}
 2505: 	self->from_charset_len = from_charset_len;
 2506: 
 2507: 	memcpy(self->to_charset, to_charset, to_charset_len);
 2508: 	self->to_charset[to_charset_len] = '\0';
 2509: 	memcpy(self->from_charset, from_charset, from_charset_len);
 2510: 	self->from_charset[from_charset_len] = '\0';
 2511: 
 2512: 	if ((iconv_t)-1 == (self->cd = iconv_open(self->to_charset, self->from_charset))) {
 2513: 		pefree(self->from_charset, persistent);
 2514: 		pefree(self->to_charset, persistent);
 2515: 		return PHP_ICONV_ERR_UNKNOWN;
 2516: 	}
 2517: 	self->persistent = persistent;
 2518: 	self->stub_len = 0;
 2519: 	return PHP_ICONV_ERR_SUCCESS;
 2520: }
 2521: /* }}} */
 2522: 
 2523: /* {{{ php_iconv_stream_filter_append_bucket */
 2524: static int php_iconv_stream_filter_append_bucket(
 2525: 		php_iconv_stream_filter *self,
 2526: 		php_stream *stream, php_stream_filter *filter,
 2527: 		php_stream_bucket_brigade *buckets_out,
 2528: 		const char *ps, size_t buf_len, size_t *consumed,
 2529: 		int persistent TSRMLS_DC)
 2530: {
 2531: 	php_stream_bucket *new_bucket;
 2532: 	char *out_buf = NULL;
 2533: 	size_t out_buf_size;
 2534: 	char *pd, *pt;
 2535: 	size_t ocnt, prev_ocnt, icnt, tcnt;
 2536: 	size_t initial_out_buf_size;
 2537: 
 2538: 	if (ps == NULL) {
 2539: 		initial_out_buf_size = 64;
 2540: 		icnt = 1;
 2541: 	} else {
 2542: 		initial_out_buf_size = buf_len;
 2543: 		icnt = buf_len;
 2544: 	}
 2545: 
 2546: 	out_buf_size = ocnt = prev_ocnt = initial_out_buf_size;
 2547: 	if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) {
 2548: 		return FAILURE;
 2549: 	}
 2550: 
 2551: 	pd = out_buf;
 2552: 
 2553: 	if (self->stub_len > 0) {
 2554: 		pt = self->stub;
 2555: 		tcnt = self->stub_len;
 2556: 
 2557: 		while (tcnt > 0) {
 2558: 			if (iconv(self->cd, &pt, &tcnt, &pd, &ocnt) == (size_t)-1) {
 2559: #if ICONV_SUPPORTS_ERRNO
 2560: 				switch (errno) {
 2561: 					case EILSEQ:
 2562: 						php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): invalid multibyte sequence", self->from_charset, self->to_charset);
 2563: 						goto out_failure;
 2564: 
 2565: 					case EINVAL:
 2566: 						if (ps != NULL) {
 2567: 							if (icnt > 0) {
 2568: 								if (self->stub_len >= sizeof(self->stub)) {
 2569: 									php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): insufficient buffer", self->from_charset, self->to_charset);
 2570: 									goto out_failure;
 2571: 								}
 2572: 								self->stub[self->stub_len++] = *(ps++);
 2573: 								icnt--;
 2574: 								pt = self->stub;
 2575: 								tcnt = self->stub_len;
 2576: 							} else {
 2577: 								tcnt = 0;
 2578: 								break;
 2579: 							}
 2580: 						}
 2581: 						break;
 2582: 
 2583: 					case E2BIG: {
 2584: 						char *new_out_buf;
 2585: 						size_t new_out_buf_size;
 2586: 
 2587: 						new_out_buf_size = out_buf_size << 1;
 2588: 
 2589: 						if (new_out_buf_size < out_buf_size) {
 2590: 							/* whoa! no bigger buckets are sold anywhere... */
 2591: 							if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
 2592: 								goto out_failure;
 2593: 							}
 2594: 
 2595: 							php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
 2596: 
 2597: 							out_buf_size = ocnt = initial_out_buf_size;
 2598: 							if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) {
 2599: 								return FAILURE;
 2600: 							}
 2601: 							pd = out_buf;
 2602: 						} else {
 2603: 							if (NULL == (new_out_buf = perealloc(out_buf, new_out_buf_size, persistent))) {
 2604: 								if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
 2605: 									goto out_failure;
 2606: 								}
 2607: 
 2608: 								php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
 2609: 								return FAILURE;
 2610: 							}
 2611: 							pd = new_out_buf + (pd - out_buf);
 2612: 							ocnt += (new_out_buf_size - out_buf_size);
 2613: 							out_buf = new_out_buf;
 2614: 							out_buf_size = new_out_buf_size;
 2615: 						}
 2616: 					} break;
 2617: 
 2618: 					default:
 2619: 						php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unknown error", self->from_charset, self->to_charset);
 2620: 						goto out_failure;
 2621: 				}
 2622: #else
 2623: 				if (ocnt == prev_ocnt) {
 2624: 					php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unknown error", self->from_charset, self->to_charset);
 2625: 					goto out_failure;
 2626: 				}
 2627: #endif
 2628: 			}
 2629: 			prev_ocnt = ocnt;
 2630: 		}
 2631: 		memmove(self->stub, pt, tcnt);
 2632: 		self->stub_len = tcnt;
 2633: 	}
 2634: 
 2635: 	while (icnt > 0) {
 2636: 		if ((ps == NULL ? iconv(self->cd, NULL, NULL, &pd, &ocnt):
 2637: 					iconv(self->cd, (char **)&ps, &icnt, &pd, &ocnt)) == (size_t)-1) {
 2638: #if ICONV_SUPPORTS_ERRNO
 2639: 			switch (errno) {
 2640: 				case EILSEQ:
 2641: 					php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): invalid multibyte sequence", self->from_charset, self->to_charset);
 2642: 					goto out_failure;
 2643: 
 2644: 				case EINVAL:
 2645: 					if (ps != NULL) {
 2646: 						if (icnt > sizeof(self->stub)) {
 2647: 							php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): insufficient buffer", self->from_charset, self->to_charset);
 2648: 							goto out_failure;
 2649: 						}
 2650: 						memcpy(self->stub, ps, icnt);
 2651: 						self->stub_len = icnt;
 2652: 						ps += icnt;
 2653: 						icnt = 0;
 2654: 					} else {
 2655: 						php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unexpected octet values", self->from_charset, self->to_charset);
 2656: 						goto out_failure;
 2657: 					}
 2658: 					break;
 2659: 
 2660: 				case E2BIG: {
 2661: 					char *new_out_buf;
 2662: 					size_t new_out_buf_size;
 2663: 
 2664: 					new_out_buf_size = out_buf_size << 1;
 2665: 
 2666: 					if (new_out_buf_size < out_buf_size) {
 2667: 						/* whoa! no bigger buckets are sold anywhere... */
 2668: 						if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
 2669: 							goto out_failure;
 2670: 						}
 2671: 
 2672: 						php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
 2673: 
 2674: 						out_buf_size = ocnt = initial_out_buf_size;
 2675: 						if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) {
 2676: 							return FAILURE;
 2677: 						}
 2678: 						pd = out_buf;
 2679: 					} else {
 2680: 						if (NULL == (new_out_buf = perealloc(out_buf, new_out_buf_size, persistent))) {
 2681: 							if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
 2682: 								goto out_failure;
 2683: 							}
 2684: 
 2685: 							php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
 2686: 							return FAILURE;
 2687: 						}
 2688: 						pd = new_out_buf + (pd - out_buf);
 2689: 						ocnt += (new_out_buf_size - out_buf_size);
 2690: 						out_buf = new_out_buf;
 2691: 						out_buf_size = new_out_buf_size;
 2692: 					}
 2693: 				} break;
 2694: 
 2695: 				default:
 2696: 					php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unknown error", self->from_charset, self->to_charset);
 2697: 					goto out_failure;
 2698: 			}
 2699: #else
 2700: 			if (ocnt == prev_ocnt) {
 2701: 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unknown error", self->from_charset, self->to_charset);
 2702: 				goto out_failure;
 2703: 			}
 2704: #endif
 2705: 		} else {
 2706: 			if (ps == NULL) {
 2707: 				break;
 2708: 			}
 2709: 		}
 2710: 		prev_ocnt = ocnt;
 2711: 	}
 2712: 
 2713: 	if (out_buf_size - ocnt > 0) {
 2714: 		if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
 2715: 			goto out_failure;
 2716: 		}
 2717: 		php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
 2718: 	} else {
 2719: 		pefree(out_buf, persistent);
 2720: 	}
 2721: 	*consumed += buf_len - icnt;
 2722: 
 2723: 	return SUCCESS;
 2724: 
 2725: out_failure:
 2726: 	pefree(out_buf, persistent);
 2727: 	return FAILURE;
 2728: }
 2729: /* }}} php_iconv_stream_filter_append_bucket */
 2730: 
 2731: /* {{{ php_iconv_stream_filter_do_filter */
 2732: static php_stream_filter_status_t php_iconv_stream_filter_do_filter(
 2733: 		php_stream *stream, php_stream_filter *filter,
 2734: 		php_stream_bucket_brigade *buckets_in,
 2735: 		php_stream_bucket_brigade *buckets_out,
 2736: 		size_t *bytes_consumed, int flags TSRMLS_DC)
 2737: {
 2738: 	php_stream_bucket *bucket = NULL;
 2739: 	size_t consumed = 0;
 2740: 	php_iconv_stream_filter *self = (php_iconv_stream_filter *)filter->abstract;
 2741: 
 2742: 	while (buckets_in->head != NULL) {
 2743: 		bucket = buckets_in->head;
 2744: 
 2745: 		php_stream_bucket_unlink(bucket TSRMLS_CC);
 2746: 
 2747: 		if (php_iconv_stream_filter_append_bucket(self, stream, filter,
 2748: 				buckets_out, bucket->buf, bucket->buflen, &consumed,
 2749: 				php_stream_is_persistent(stream) TSRMLS_CC) != SUCCESS) {
 2750: 			goto out_failure;
 2751: 		}
 2752: 
 2753: 		php_stream_bucket_delref(bucket TSRMLS_CC);
 2754: 	}
 2755: 
 2756: 	if (flags != PSFS_FLAG_NORMAL) {
 2757: 		if (php_iconv_stream_filter_append_bucket(self, stream, filter,
 2758: 				buckets_out, NULL, 0, &consumed,
 2759: 				php_stream_is_persistent(stream) TSRMLS_CC) != SUCCESS) {
 2760: 			goto out_failure;
 2761: 		}
 2762: 	}
 2763: 
 2764: 	if (bytes_consumed != NULL) {
 2765: 		*bytes_consumed = consumed;
 2766: 	}
 2767: 
 2768: 	return PSFS_PASS_ON;
 2769: 
 2770: out_failure:
 2771: 	if (bucket != NULL) {
 2772: 		php_stream_bucket_delref(bucket TSRMLS_CC);
 2773: 	}
 2774: 	return PSFS_ERR_FATAL;
 2775: }
 2776: /* }}} */
 2777: 
 2778: /* {{{ php_iconv_stream_filter_cleanup */
 2779: static void php_iconv_stream_filter_cleanup(php_stream_filter *filter TSRMLS_DC)
 2780: {
 2781: 	php_iconv_stream_filter_dtor((php_iconv_stream_filter *)filter->abstract);
 2782: 	pefree(filter->abstract, ((php_iconv_stream_filter *)filter->abstract)->persistent);
 2783: }
 2784: /* }}} */
 2785: 
 2786: static php_stream_filter_ops php_iconv_stream_filter_ops = {
 2787: 	php_iconv_stream_filter_do_filter,
 2788: 	php_iconv_stream_filter_cleanup,
 2789: 	"convert.iconv.*"
 2790: };
 2791: 
 2792: /* {{{ php_iconv_stream_filter_create */
 2793: static php_stream_filter *php_iconv_stream_filter_factory_create(const char *name, zval *params, int persistent TSRMLS_DC)
 2794: {
 2795: 	php_stream_filter *retval = NULL;
 2796: 	php_iconv_stream_filter *inst;
 2797: 	char *from_charset = NULL, *to_charset = NULL;
 2798: 	size_t from_charset_len, to_charset_len;
 2799: 
 2800: 	if ((from_charset = strchr(name, '.')) == NULL) {
 2801: 		return NULL;
 2802: 	}
 2803: 	++from_charset;
 2804: 	if ((from_charset = strchr(from_charset, '.')) == NULL) {
 2805: 		return NULL;
 2806: 	}
 2807: 	++from_charset;
 2808: 	if ((to_charset = strpbrk(from_charset, "/.")) == NULL) {
 2809: 		return NULL;
 2810: 	}
 2811: 	from_charset_len = to_charset - from_charset;
 2812: 	++to_charset;
 2813: 	to_charset_len = strlen(to_charset);
 2814: 
 2815: 	if (from_charset_len >= ICONV_CSNMAXLEN || to_charset_len >= ICONV_CSNMAXLEN) {
 2816: 		return NULL;
 2817: 	}
 2818: 
 2819: 	if (NULL == (inst = pemalloc(sizeof(php_iconv_stream_filter), persistent))) {
 2820: 		return NULL;
 2821: 	}
 2822: 
 2823: 	if (php_iconv_stream_filter_ctor(inst, to_charset, to_charset_len, from_charset, from_charset_len, persistent) != PHP_ICONV_ERR_SUCCESS) {
 2824: 		pefree(inst, persistent);
 2825: 		return NULL;
 2826: 	}
 2827: 
 2828: 	if (NULL == (retval = php_stream_filter_alloc(&php_iconv_stream_filter_ops, inst, persistent))) {
 2829: 		php_iconv_stream_filter_dtor(inst);
 2830: 		pefree(inst, persistent);
 2831: 	}
 2832: 
 2833: 	return retval;
 2834: }
 2835: /* }}} */
 2836: 
 2837: /* {{{ php_iconv_stream_register_factory */
 2838: static php_iconv_err_t php_iconv_stream_filter_register_factory(TSRMLS_D)
 2839: {
 2840: 	static php_stream_filter_factory filter_factory = {
 2841: 		php_iconv_stream_filter_factory_create
 2842: 	};
 2843: 
 2844: 	if (FAILURE == php_stream_filter_register_factory(
 2845: 				php_iconv_stream_filter_ops.label,
 2846: 				&filter_factory TSRMLS_CC)) {
 2847: 		return PHP_ICONV_ERR_UNKNOWN;
 2848: 	}
 2849: 	return PHP_ICONV_ERR_SUCCESS;
 2850: }
 2851: /* }}} */
 2852: 
 2853: /* {{{ php_iconv_stream_unregister_factory */
 2854: static php_iconv_err_t php_iconv_stream_filter_unregister_factory(TSRMLS_D)
 2855: {
 2856: 	if (FAILURE == php_stream_filter_unregister_factory(
 2857: 				php_iconv_stream_filter_ops.label TSRMLS_CC)) {
 2858: 		return PHP_ICONV_ERR_UNKNOWN;
 2859: 	}
 2860: 	return PHP_ICONV_ERR_SUCCESS;
 2861: }
 2862: /* }}} */
 2863: /* }}} */
 2864: #endif
 2865: 
 2866: /*
 2867:  * Local variables:
 2868:  * tab-width: 4
 2869:  * c-basic-offset: 4
 2870:  * End:
 2871:  * vim600: sw=4 ts=4 fdm=marker
 2872:  * vim<600: sw=4 ts=4
 2873:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>