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);
} 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
goto out;
case E2BIG:
+ if (prev_in_left == in_left) {
+ err = PHP_ICONV_ERR_UNKNOWN;
+ goto out;
+ }
break;
default:
#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;
}
}
+ 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;
}
}