moriyoshi Sun Dec 21 20:30:02 2003 EDT Modified files: /php-src/ext/iconv iconv.c Log: - Fix multibyte handling errors in iconv_mime_encode() when quoted-printable encoding scheme is used. - Fix segfault that occurs in iconv_mime_encode() when input_charset or output_charset parameter is not specified in the associative array. Index: php-src/ext/iconv/iconv.c diff -u php-src/ext/iconv/iconv.c:1.109 php-src/ext/iconv/iconv.c:1.110 --- php-src/ext/iconv/iconv.c:1.109 Sun Dec 7 19:38:00 2003 +++ php-src/ext/iconv/iconv.c Sun Dec 21 20:30:00 2003 @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: iconv.c,v 1.109 2003/12/08 00:38:00 moriyoshi Exp $ */ +/* $Id: iconv.c,v 1.110 2003/12/22 01:30:00 moriyoshi Exp $ */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -911,6 +911,24 @@ size_t in_left; char *out_p; size_t out_left; + static int qp_table[256] = { + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x00 */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x10 */ + 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x20 */ + 1, 1, 1, 1, 1, 1, 1 ,1, 1, 1, 1, 1, 1, 3, 1, 3, /* 0x30 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, /* 0x50 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, /* 0x70 */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x80 */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x90 */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xA0 */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xB0 */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xC0 */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xD0 */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xE0 */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 /* 0xF0 */ + }; out_charset_len = strlen(out_charset); lfchars_len = strlen(lfchars); @@ -1086,16 +1104,26 @@ } break; /* case PHP_ICONV_ENC_SCHEME_BASE64: */ case PHP_ICONV_ENC_SCHEME_QPRINT: { + size_t ini_in_left; + const char *ini_in_p; + const unsigned char *p; + size_t nbytes_required; + smart_str_appendc(pretval, 'Q'); char_cnt--; smart_str_appendc(pretval, '?'); char_cnt--; - prev_in_left = in_left; + prev_in_left = ini_in_left = in_left; + ini_in_p = in_p; + + for (out_size = char_cnt; out_size > 0;) { + size_t prev_out_left; + + nbytes_required = 0; - while (in_left > 0) { out_p = buf; - out_left = out_size = 1; + out_left = out_size; if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) { #if ICONV_SUPPORTS_ERRNO @@ -1109,6 +1137,10 @@ goto out; case E2BIG: + if (prev_in_left == in_left) { + err = PHP_ICONV_ERR_UNKNOWN; + goto out; + } break; default: @@ -1123,36 +1155,47 @@ #endif } - if (out_size > out_left) { - if ((buf[0] >= 33 && buf[0] <= 60) || - (buf[0] >= 62 && buf[0] <= 126)) { - - if (char_cnt >= 1 + 2) { - smart_str_appendc(pretval, buf[0]); - char_cnt--; - } else { - in_p -= (prev_in_left - in_left); - in_left = prev_in_left; + prev_out_left = out_left; + if (iconv(cd, NULL, NULL, (char **) &out_p, &out_left) == (size_t)-1) { +#if ICONV_SUPPORTS_ERRNO + if (errno != E2BIG) { + err = PHP_ICONV_ERR_UNKNOWN; + goto out; + } +#else + if (out_left == prev_out_left) { + err = PHP_ICONV_ERR_UNKNOWN; + goto out; + } +#endif + } - break; - } - } else { - if (char_cnt >= 3 + 2) { - static char qp_digits[] = "0123456789ABCDEF"; - smart_str_appendc(pretval, '='); - smart_str_appendc(pretval, qp_digits[(buf[0] >> 4) & 0x0f]); - smart_str_appendc(pretval, qp_digits[(buf[0] & 0x0f)]); - char_cnt -= 3; - } else { - in_p -= (prev_in_left - in_left); - in_left = prev_in_left; + for (p = (unsigned char *)buf; p < (unsigned char *)out_p; p++) { + nbytes_required += qp_table[*p]; + } - break; - } - } + if (nbytes_required <= char_cnt - 2) { + break; + } + + out_size -= ((nbytes_required - (char_cnt - 2)) + 1) / (3 - 1); + in_left = ini_in_left; + in_p = ini_in_p; + } + + for (p = (unsigned char *)buf; p < (unsigned char *)out_p; p++) { + if (qp_table[*p] == 1) { + smart_str_appendc(pretval, *(char *)p); + char_cnt--; + } else { + static char qp_digits[] = "0123456789ABCDEF"; + smart_str_appendc(pretval, '='); + smart_str_appendc(pretval, qp_digits[(*p >> 4) & 0x0f]); + smart_str_appendc(pretval, qp_digits[(*p & 0x0f)]); + char_cnt -= 3; } - prev_in_left = in_left; } + prev_in_left = in_left; smart_str_appendl(pretval, "?=", sizeof("?=") - 1); char_cnt -= 2; @@ -1904,19 +1947,19 @@ } } + in_charset = ICONVG(internal_encoding); + if (zend_hash_find(Z_ARRVAL_P(pref), "input-charset", sizeof("input-charset"), (void **)&ppval) == SUCCESS) { if (Z_TYPE_PP(ppval) == IS_STRING && Z_STRLEN_PP(ppval) > 0) { in_charset = Z_STRVAL_PP(ppval); - } else { - in_charset = ICONVG(internal_encoding); } } + out_charset = in_charset; + if (zend_hash_find(Z_ARRVAL_P(pref), "output-charset", sizeof("output-charset"), (void **)&ppval) == SUCCESS) { if (Z_TYPE_PP(ppval) == IS_STRING && Z_STRLEN_PP(ppval) > 0) { out_charset = Z_STRVAL_PP(ppval); - } else { - out_charset = in_charset; } }
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php