Skip to content

Commit 04df7e3

Browse files
committed
Make php_stream_write_buffer() return characters written, not bytes
1 parent 8c8ac48 commit 04df7e3

File tree

1 file changed

+34
-5
lines changed

1 file changed

+34
-5
lines changed

main/streams/streams.c

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1128,7 +1128,8 @@ PHPAPI char *php_stream_get_record(php_stream *stream, size_t maxlen, size_t *re
11281128
/* Writes a buffer directly to a stream, using multiple of the chunk size */
11291129
static size_t _php_stream_write_buffer(php_stream *stream, int buf_type, zstr buf, int buflen TSRMLS_DC)
11301130
{
1131-
size_t didwrite = 0, towrite, justwrote;
1131+
size_t didwrite = 0, towrite, justwrote, shouldwrite, buflen_orig = buflen;
1132+
zstr buf_orig = buf;
11321133
char *freeme = NULL;
11331134

11341135
/* if we have a seekable stream we need to ensure that data is written at the
@@ -1155,6 +1156,8 @@ static size_t _php_stream_write_buffer(php_stream *stream, int buf_type, zstr bu
11551156
}
11561157
}
11571158

1159+
shouldwrite = buflen;
1160+
11581161
while (buflen > 0) {
11591162
towrite = buflen;
11601163
if (towrite > stream->chunk_size) {
@@ -1179,6 +1182,36 @@ static size_t _php_stream_write_buffer(php_stream *stream, int buf_type, zstr bu
11791182
}
11801183
}
11811184

1185+
1186+
if (stream->output_encoding) {
1187+
/* Map didwrite back to the original character count */
1188+
if (didwrite == shouldwrite) {
1189+
/* Everything wrote okay, no need to count */
1190+
didwrite = buflen_orig;
1191+
} else {
1192+
UErrorCode status = U_ZERO_ERROR;
1193+
char *t = freeme;
1194+
UChar *p = buf_orig.u;
1195+
1196+
switch (ucnv_getType(stream->output_encoding)) {
1197+
case UCNV_SBCS:
1198+
case UCNV_LATIN_1:
1199+
case UCNV_US_ASCII:
1200+
/* 1:1 character->byte mapping, didwrite really does mean the number of characters written */
1201+
break;
1202+
default:
1203+
/* Reconvert into junk buffer to see where conversion stops in source string */
1204+
ucnv_resetFromUnicode(stream->output_encoding);
1205+
ucnv_fromUnicode(stream->output_encoding, &t, t + didwrite, &p, p + buflen_orig, NULL, TRUE, &status);
1206+
/* p stops at the first unconvertable UChar when t runs out of space */
1207+
didwrite = p - buf_orig.u;
1208+
}
1209+
}
1210+
} else if (buf_type == IS_UNICODE) {
1211+
/* Was slopily converted */
1212+
didwrite /= UBYTES(1);
1213+
}
1214+
11821215
if (freeme) {
11831216
efree(freeme);
11841217
}
@@ -1296,10 +1329,6 @@ PHPAPI size_t _php_stream_write_unicode(php_stream *stream, const UChar *buf, in
12961329
ret = _php_stream_write_buffer(stream, IS_UNICODE, (zstr)((UChar*)buf), count TSRMLS_CC);
12971330
}
12981331

1299-
/* Return data points, not bytes */
1300-
if (ret > 0) {
1301-
ret >>= 1;
1302-
}
13031332
return ret;
13041333
}
13051334

0 commit comments

Comments
 (0)