Browse Source

- 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.
PEAR_1_4DEV
Moriyoshi Koizumi 23 years ago
parent
commit
1b239fc970
  1. 107
      ext/iconv/iconv.c

107
ext/iconv/iconv.c

@ -911,6 +911,24 @@ static php_iconv_err_t _php_iconv_mime_encode(smart_str *pretval, const char *fn
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 @@ static php_iconv_err_t _php_iconv_mime_encode(smart_str *pretval, const char *fn
} 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 @@ static php_iconv_err_t _php_iconv_mime_encode(smart_str *pretval, const char *fn
goto out;
case E2BIG:
if (prev_in_left == in_left) {
err = PHP_ICONV_ERR_UNKNOWN;
goto out;
}
break;
default:
@ -1123,36 +1155,47 @@ static php_iconv_err_t _php_iconv_mime_encode(smart_str *pretval, const char *fn
#endif
}
if (out_size > out_left) {
if ((buf[0] >= 33 && buf[0] <= 60) ||
(buf[0] >= 62 && buf[0] <= 126)) {
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
}
for (p = (unsigned char *)buf; p < (unsigned char *)out_p; p++) {
nbytes_required += qp_table[*p];
}
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;
if (nbytes_required <= char_cnt - 2) {
break;
}
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;
out_size -= ((nbytes_required - (char_cnt - 2)) + 1) / (3 - 1);
in_left = ini_in_left;
in_p = ini_in_p;
}
break;
}
}
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 @@ PHP_FUNCTION(iconv_mime_encode)
}
}
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;
}
}

Loading…
Cancel
Save