From b5b0a53b09776f74ab4ddf6b9468ab1b41267ab5 Mon Sep 17 00:00:00 2001 From: Michael M Slusarz Date: Sun, 24 Feb 2013 18:34:35 -0700 Subject: [PATCH] Fix #64166: quoted-printable-encode stream filter incorrectly discarding whitespace Second attempt: need to use lookaheadto determine whether to encode ws --- ext/standard/filters.c | 58 +++++++++++++++++------- ext/standard/tests/streams/bug64166.phpt | 52 +++++++++++++-------- 2 files changed, 74 insertions(+), 36 deletions(-) diff --git a/ext/standard/filters.c b/ext/standard/filters.c index 21e165b6c2..99a39be9a1 100644 --- a/ext/standard/filters.c +++ b/ext/standard/filters.c @@ -791,7 +791,7 @@ static php_conv_err_t php_conv_qprint_encode_convert(php_conv_qprint_encode *ins unsigned int line_ccnt; unsigned int lb_ptr; unsigned int lb_cnt; - unsigned int prev_ws; + unsigned int trail_ws; int opts; static char qp_digits[] = "0123456789ABCDEF"; @@ -808,7 +808,7 @@ static php_conv_err_t php_conv_qprint_encode_convert(php_conv_qprint_encode *ins icnt = *in_left_p; pd = (unsigned char *)(*out_pp); ocnt = *out_left_p; - prev_ws = 0; + trail_ws = 0; for (;;) { if (!(opts & PHP_CONV_QPRINT_OPT_BINARY) && inst->lbchars != NULL && inst->lbchars_len > 0) { @@ -827,14 +827,6 @@ static php_conv_err_t php_conv_qprint_encode_convert(php_conv_qprint_encode *ins break; } - /* If the character(s) immediately before the line break - * is whitespace, need to convert to soft linebreak to - * preserve that data. */ - if (prev_ws > 0) { - *(pd++) = '='; - ocnt--; - } - for (i = 0; i < lb_cnt; i++) { *(pd++) = inst->lbchars[i]; ocnt--; @@ -852,9 +844,10 @@ static php_conv_err_t php_conv_qprint_encode_convert(php_conv_qprint_encode *ins } c = NEXT_CHAR(ps, icnt, lb_ptr, lb_cnt, inst->lbchars); - prev_ws = 0; - if (!(opts & PHP_CONV_QPRINT_OPT_BINARY) && (c == '\t' || c == ' ')) { + if (!(opts & PHP_CONV_QPRINT_OPT_BINARY) && + (trail_ws == 0) && + (c == '\t' || c == ' ')) { if (line_ccnt < 2 && inst->lbchars != NULL) { if (ocnt < inst->lbchars_len + 1) { err = PHP_CONV_ERR_TOO_BIG; @@ -874,11 +867,41 @@ static php_conv_err_t php_conv_qprint_encode_convert(php_conv_qprint_encode *ins err = PHP_CONV_ERR_TOO_BIG; break; } - *(pd++) = c; - ocnt--; - line_ccnt--; - prev_ws = 1; - CONSUME_CHAR(ps, icnt, lb_ptr, lb_cnt); + + /* Check to see if this is EOL whitespace. */ + if (inst->lbchars != NULL) { + unsigned int j, lb_cnt2; + lb_cnt2 = 0; + unsigned char *ps2; + ps2 = ps; + trail_ws = 1; + + for (j = icnt - 1; j > 0; j--, ps2++) { + if (*ps2 == inst->lbchars[lb_cnt2]) { + lb_cnt2++; + if (lb_cnt2 >= inst->lbchars_len) { + /* Found trailing ws. Reset to top of main + * for loop to allow for code to do necessary + * wrapping/encoding. */ + break; + } + } else if (lb_cnt2 != 0 || (*ps2 != '\t' && *ps2 != ' ')) { + /* At least one non-EOL character following, so + * don't need to encode ws. */ + trail_ws = 0; + break; + } else { + trail_ws++; + } + } + } + + if (trail_ws == 0) { + *(pd++) = c; + ocnt--; + line_ccnt--; + CONSUME_CHAR(ps, icnt, lb_ptr, lb_cnt); + } } } else if ((!(opts & PHP_CONV_QPRINT_OPT_FORCE_ENCODE_FIRST) || line_ccnt < inst->line_len) && ((c >= 33 && c <= 60) || (c >= 62 && c <= 126))) { if (line_ccnt < 2 && inst->lbchars != NULL) { @@ -927,6 +950,7 @@ static php_conv_err_t php_conv_qprint_encode_convert(php_conv_qprint_encode *ins *(pd++) = qp_digits[(c & 0x0f)]; ocnt -= 3; line_ccnt -= 3; + trail_ws--; CONSUME_CHAR(ps, icnt, lb_ptr, lb_cnt); } } diff --git a/ext/standard/tests/streams/bug64166.phpt b/ext/standard/tests/streams/bug64166.phpt index b9a7a052a4..e725a4b698 100644 --- a/ext/standard/tests/streams/bug64166.phpt +++ b/ext/standard/tests/streams/bug64166.phpt @@ -2,31 +2,45 @@ Bug #64166: quoted-printable-encode stream filter incorrectly discarding whitespace --FILE-- "\n", - 'line-length' => 7 -)); -var_dump(stream_get_contents($fd, -1, 0)); + $res = stream_filter_append($fd, 'convert.quoted-printable-encode', STREAM_FILTER_READ, array( + 'line-break-chars' => "\n", + 'line-length' => 74 + )); + var_dump(stream_get_contents($fd, -1, 0)); -stream_filter_remove($res); + stream_filter_remove($res); + + rewind($fd); + stream_filter_append($fd, 'convert.quoted-printable-encode', STREAM_FILTER_READ, array( + 'line-break-chars' => "\n", + 'line-length' => 6 + )); + var_dump(stream_get_contents($fd, -1, 0)); + + fclose($fd); +} + +test_64166("FIRST \nSECOND"); +test_64166("FIRST \nSECOND"); -rewind($fd); -stream_filter_append($fd, 'convert.quoted-printable-encode', STREAM_FILTER_READ, array( - 'line-break-chars' => "\n", - 'line-length' => 6 -)); -var_dump(stream_get_contents($fd, -1, 0)); ?> --EXPECT-- -string(14) "FIRST = +string(15) "FIRST=20 +SECOND" +string(19) "FIRST= +=20 +SECON= +D" +string(18) "FIRST=20=20 SECOND" -string(18) "FIRST= - = +string(24) "FIRST= +=20= +=20 SECON= D" -- 2.40.0