Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Fix #64166: quoted-printable-encode stream filter incorrectly discarding... #272

Closed
wants to merge 4 commits into from

4 participants

@slusarz

... whitespace

If trailing whitespace on a line is detected, mark the linebreak as a
soft linebreak.

@slusarz slusarz Fix #64166: quoted-printable-encode stream filter incorrectly discard…
…ing whitespace

If trailing whitespace on a line is detected, mark the linebreak as a
soft linebreak.
bfffa7d
ext/standard/tests/streams/bug64166.phpt
((12 lines not shown))
+ 'line-break-chars' => "\n",
+ 'line-length' => 7
+));
+var_dump(stream_get_contents($fd, -1, 0));
+
+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));
+?>
+--EXPECT--
+string(14) "FIRST =
@smalyshev Owner

Why this produces "FIRST{SPACE}" when quoted_printable_encode in this situation produces "FIRST=20"?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@smalyshev
Owner

This patch seems to work differently with join and split writes:

<?php
$data1 = "FIRST ";
$data2 = "\nSECOND";

$fd = fopen('t', 'w+');

$res = stream_filter_append($fd, 'convert.quoted-printable-encode', STREAM_FILTER_WRITE, array(
        'line-break-chars' => "\n",
        'line-length' => 7
));
fwrite($fd, $data1);
fwrite($fd, $data2);
//fwrite($fd, $data1.$data2);
fclose($fd);
var_dump(file_get_contents('t'));

If I do split write, I get this:
string(13) "FIRST
SECOND"
If I do joint write, I get this:
string(14) "FIRST =
SECOND"

I don't think this is a right behavior.

@slusarz slusarz Fix #64166: quoted-printable-encode stream filter incorrectly discard…
…ing whitespace

Second attempt: need to use lookaheadto determine whether to encode ws
f4d8330
@slusarz

Things should be fixed now.

@weltling

declarations should be at the top of the nearest block

@php-pulls
Collaborator

Comment on behalf of stas at php.net:

merged

@php-pulls php-pulls closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Feb 7, 2013
  1. @slusarz

    Fix #64166: quoted-printable-encode stream filter incorrectly discard…

    slusarz authored
    …ing whitespace
    
    If trailing whitespace on a line is detected, mark the linebreak as a
    soft linebreak.
Commits on Feb 25, 2013
  1. @slusarz

    Fix #64166: quoted-printable-encode stream filter incorrectly discard…

    slusarz authored
    …ing whitespace
    
    Second attempt: need to use lookaheadto determine whether to encode ws
Commits on Mar 18, 2013
  1. @slusarz

    trailing ws

    slusarz authored
  2. @slusarz
This page is out of date. Refresh to see the latest.
Showing with 93 additions and 10 deletions.
  1. +47 −10 ext/standard/filters.c
  2. +46 −0 ext/standard/tests/streams/bug64166.phpt
View
57 ext/standard/filters.c
@@ -771,7 +771,7 @@ static void php_conv_qprint_encode_dtor(php_conv_qprint_encode *inst)
}
#define NEXT_CHAR(ps, icnt, lb_ptr, lb_cnt, lbchars) \
- ((lb_ptr) < (lb_cnt) ? (lbchars)[(lb_ptr)] : *(ps))
+ ((lb_ptr) < (lb_cnt) ? (lbchars)[(lb_ptr)] : *(ps))
#define CONSUME_CHAR(ps, icnt, lb_ptr, lb_cnt) \
if ((lb_ptr) < (lb_cnt)) { \
@@ -791,6 +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 trail_ws;
int opts;
static char qp_digits[] = "0123456789ABCDEF";
@@ -807,6 +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;
+ trail_ws = 0;
for (;;) {
if (!(opts & PHP_CONV_QPRINT_OPT_BINARY) && inst->lbchars != NULL && inst->lbchars_len > 0) {
@@ -839,11 +841,13 @@ static php_conv_err_t php_conv_qprint_encode_convert(php_conv_qprint_encode *ins
if (lb_ptr >= lb_cnt && icnt <= 0) {
break;
- }
+ }
c = NEXT_CHAR(ps, icnt, lb_ptr, lb_cnt, inst->lbchars);
- 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;
@@ -863,12 +867,44 @@ 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--;
- CONSUME_CHAR(ps, icnt, lb_ptr, lb_cnt);
+
+ /* Check to see if this is EOL whitespace. */
+ if (inst->lbchars != NULL) {
+ unsigned char *ps2;
+ unsigned int j, lb_cnt2;
+
+ lb_cnt2 = 0;
+ 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))) {
+ } 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) {
if (ocnt < inst->lbchars_len + 1) {
err = PHP_CONV_ERR_TOO_BIG;
@@ -912,9 +948,10 @@ static php_conv_err_t php_conv_qprint_encode_convert(php_conv_qprint_encode *ins
}
*(pd++) = '=';
*(pd++) = qp_digits[(c >> 4)];
- *(pd++) = qp_digits[(c & 0x0f)];
+ *(pd++) = qp_digits[(c & 0x0f)];
ocnt -= 3;
line_ccnt -= 3;
+ trail_ws--;
CONSUME_CHAR(ps, icnt, lb_ptr, lb_cnt);
}
}
@@ -922,7 +959,7 @@ static php_conv_err_t php_conv_qprint_encode_convert(php_conv_qprint_encode *ins
*in_pp = (const char *)ps;
*in_left_p = icnt;
*out_pp = (char *)pd;
- *out_left_p = ocnt;
+ *out_left_p = ocnt;
inst->line_ccnt = line_ccnt;
inst->lb_ptr = lb_ptr;
inst->lb_cnt = lb_cnt;
View
46 ext/standard/tests/streams/bug64166.phpt
@@ -0,0 +1,46 @@
+--TEST--
+Bug #64166: quoted-printable-encode stream filter incorrectly discarding whitespace
+--FILE--
+<?php
+
+function test_64166($data) {
+ $fd = fopen('php://temp', 'w+');
+ fwrite($fd, $data);
+ rewind($fd);
+
+ $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);
+
+ 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");
+
+?>
+--EXPECT--
+string(15) "FIRST=20
+SECOND"
+string(19) "FIRST=
+=20
+SECON=
+D"
+string(18) "FIRST=20=20
+SECOND"
+string(24) "FIRST=
+=20=
+=20
+SECON=
+D"
Something went wrong with that request. Please try again.