cvs: php-src /ext/bz2 bz2_filter.c /ext/standard file.c filters.c streamsfuncs.c user_filters.c /ext/unicode unicode_filter.c /ext/zlib
zlib_filter.c /main php_streams.h /main/streams cast.c filter.c php_stream_filter_api.h streams.c

From: Date: Mon, 13 Mar 2006 04:40:12 +0000
Subject: cvs: php-src /ext/bz2 bz2_filter.c /ext/standard file.c filters.c streamsfuncs.c user_filters.c /ext/unicode unicode_filter.c /ext/zlib
zlib_filter.c /main php_streams.h /main/streams cast.c filter.c php_stream_filter_api.h streams.c
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-37242@lists.php.net to get a copy of this message
pollita Mon Mar 13 04:40:12 2006 UTC Modified files: /php-src/main php_streams.h /php-src/main/streams streams.c filter.c cast.c php_stream_filter_api.h /php-src/ext/standard file.c user_filters.c filters.c streamsfuncs.c /php-src/ext/zlib zlib_filter.c /php-src/ext/bz2 bz2_filter.c /php-src/ext/unicode unicode_filter.c Log: Refactor streams layer for PHP6. Don't be frightened by the size of this commit. A significant portion of it is restoring the read buffer semantics back to what PHP4/5 use. (Or a close aproximation thereof). See main/streams/streams.c and ext/standard/file.c for a set of UTODO comments covering work yet to be done.

http://cvs.php.net/viewcvs.cgi/php-src/main/php_streams.h?r1=1.105&r2=1.106&diff_format=u Index: php-src/main/php_streams.h diff -u php-src/main/php_streams.h:1.105 php-src/main/php_streams.h:1.106 --- php-src/main/php_streams.h:1.105 Sun Jan 1 13:09:57 2006 +++ php-src/main/php_streams.h Mon Mar 13 04:40:11 2006 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_streams.h,v 1.105 2006/01/01 13:09:57 sniper Exp $ */ +/* $Id: php_streams.h,v 1.106 2006/03/13 04:40:11 pollita Exp $ */ #ifndef PHP_STREAMS_H #define PHP_STREAMS_H @@ -206,11 +206,16 @@ php_stream_context *context; int flags; /* PHP_STREAM_FLAG_XXX */ + /* unicode */ + UConverter *input_encoding; + UConverter *output_encoding; + /* buffer */ off_t position; /* of underlying stream */ - - php_stream_bucket_brigade readbuf; - off_t readbuf_ofs, readbuf_avail; + zstr readbuf; /* readbuf.s or readbuf.u */ + size_t readbuflen; /* Length in units (char or UChar) */ + off_t readpos; /* Position in units (char or UChar) */ + off_t writepos; /* how much data to read when filling buffer */ size_t chunk_size; @@ -230,7 +235,6 @@ END_EXTERN_C() #define php_stream_alloc(ops, thisptr, persistent_id, mode) _php_stream_alloc((ops), (thisptr), (persistent_id), (mode) STREAMS_CC TSRMLS_CC) - #define php_stream_get_resource_id(stream) (stream)->rsrc_id #if ZEND_DEBUG /* use this to tell the stream that it is OK if we don't explicitly close it */ @@ -247,6 +251,10 @@ #define php_stream_from_zval(xstr, ppzval) ZEND_FETCH_RESOURCE2((xstr), php_stream *, (ppzval), -1, "stream", php_file_le_stream(), php_file_le_pstream()) #define php_stream_from_zval_no_verify(xstr, ppzval) (xstr) = (php_stream*)zend_fetch_resource((ppzval) TSRMLS_CC, -1, "stream", NULL, 2, php_file_le_stream(), php_file_le_pstream()) +#define PS_ULEN(is_unicode, len) ((is_unicode) ? UBYTES(len) : (len)) +#define php_stream_reads_unicode(stream) ((stream->input_encoding) ? 1 : 0) +#define php_stream_writes_unicode(stream) ((stream->output_encoding) ? 1 : 0) + BEGIN_EXTERN_C() PHPAPI int php_stream_from_persistent_id(const char *persistent_id, php_stream **stream TSRMLS_DC); #define PHP_STREAM_PERSISTENT_SUCCESS 0 /* id exists */ @@ -279,20 +287,22 @@ #define php_stream_read(stream, buf, count) _php_stream_read((stream), (buf), (count) TSRMLS_CC) /* Convert using runtime_encoding if necessary -- return unicode */ -PHPAPI size_t _php_stream_read_unicode(php_stream *stream, UChar *buf, int32_t size TSRMLS_DC); -#define php_stream_read_unicode(stream, buf, size) _php_stream_read_unicode((stream), (buf), (size) TSRMLS_CC) +PHPAPI size_t _php_stream_read_unicode(php_stream *stream, UChar *buf, int maxlen, int maxchars TSRMLS_DC); +#define php_stream_read_unicode(stream, buf, maxlen) _php_stream_read_unicode((stream), (buf), (maxlen), -1 TSRMLS_CC) -/* Read count data points (char or UChar) until buffered type changes -- return single type without conversion */ -PHPAPI void *_php_stream_u_read(php_stream *stream, void *buf, int32_t *pnum_bytes, int32_t *pnum_chars, int *pis_unicode TSRMLS_DC); -#define php_stream_u_read(stream, buf, pnum_bytes, pnum_chars, pis_unicode) \ - _php_stream_u_read((stream), (buf), (pnum_bytes), (pnum_chars), (pis_unicode) TSRMLS_CC) +PHPAPI UChar *_php_stream_read_unicode_chars(php_stream *stream, int *pchars TSRMLS_DC); +#define php_stream_read_unicode_chars(stream, pchars) _php_stream_read_unicode_chars((stream), (pchars) TSRMLS_CC) PHPAPI size_t _php_stream_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC); #define php_stream_write_string(stream, str) _php_stream_write(stream, str, strlen(str) TSRMLS_CC) #define php_stream_write(stream, buf, count) _php_stream_write(stream, (buf), (count) TSRMLS_CC) -PHPAPI size_t _php_stream_u_write(php_stream *stream, const UChar *buf, int32_t count TSRMLS_DC); -#define php_stream_u_write(stream, buf, count) _php_stream_u_write((stream), (buf), (count) TSRMLS_CC) +PHPAPI size_t _php_stream_write_unicode(php_stream *stream, const UChar *buf, int count TSRMLS_DC); +#define php_stream_write_unicode(stream, buf, count) _php_stream_write_unicode((stream), (buf), (count) TSRMLS_CC) + +#define php_stream_u_write(stream, type, zbuf, buflen) ((type == IS_UNICODE) ? \ + php_stream_write_unicode((stream), (zbuf).u, (buflen)) : \ + php_stream_write((stream), (zbuf).s, (buflen))) PHPAPI size_t _php_stream_printf(php_stream *stream TSRMLS_DC, const char *fmt, ...); /* php_stream_printf macro & function require TSRMLS_CC */ @@ -302,7 +312,7 @@ #define php_stream_eof(stream) _php_stream_eof((stream) TSRMLS_CC) PHPAPI int _php_stream_getc(php_stream *stream TSRMLS_DC); -#define php_stream_getc(stream) _php_stream_getc((stream) TSRMLS_CC) +#define php_stream_getc(stream) _php_stream_getc((stream) TSRMLS_CC) PHPAPI int _php_stream_putc(php_stream *stream, int c TSRMLS_DC); #define php_stream_putc(stream, c) _php_stream_putc((stream), (c) TSRMLS_CC) @@ -310,24 +320,19 @@ PHPAPI int _php_stream_flush(php_stream *stream, int closing TSRMLS_DC); #define php_stream_flush(stream) _php_stream_flush((stream), 0 TSRMLS_CC) -PHPAPI void _php_stream_flush_readbuf(php_stream *stream TSRMLS_DC); -#define php_stream_flush_readbuf(stream) _php_stream_flush_readbuf((stream) TSRMLS_CC) - PHPAPI char *_php_stream_get_line(php_stream *stream, char *buf, size_t maxlen, size_t *returned_len TSRMLS_DC); #define php_stream_gets(stream, buf, maxlen) _php_stream_get_line((stream), (buf), (maxlen), NULL TSRMLS_CC) + #define php_stream_get_line(stream, buf, maxlen, retlen) _php_stream_get_line((stream), (buf), (maxlen), (retlen) TSRMLS_CC) PHPAPI char *php_stream_get_record(php_stream *stream, size_t maxlen, size_t *returned_len, char *delim, size_t delim_len TSRMLS_DC); -PHPAPI UChar *_php_stream_u_get_line(php_stream *stream, UChar *buf, int32_t *pmax_u16, int32_t *pmax_chars, int *pis_unicode TSRMLS_DC); -#define php_stream_u_get_line(stream, buf, max_u16, max_chars, is_unicode) _php_stream_u_get_line((stream), (buf), (max_u16), (max_chars), (is_unicode) TSRMLS_CC) +PHPAPI UChar *_php_stream_u_get_line(php_stream *stream, UChar *buf, int32_t *pmax_bytes, int32_t *pmax_chars, int *pis_unicode TSRMLS_DC); +#define php_stream_u_get_line(stream, buf, maxlen_buf, maxlen_chars, buf_type) _php_stream_u_get_line((stream), (buf), (maxlen_buf), (maxlen_chars), (buf_type) TSRMLS_CC) /* CAREFUL! this is equivalent to puts NOT fputs! */ PHPAPI int _php_stream_puts(php_stream *stream, char *buf TSRMLS_DC); #define php_stream_puts(stream, buf) _php_stream_puts((stream), (buf) TSRMLS_CC) -PHPAPI int _php_stream_will_read_unicode(php_stream *stream TSRMLS_DC); -#define php_stream_will_read_unicode(stream) _php_stream_will_read_unicode((stream) TSRMLS_CC); - PHPAPI int _php_stream_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC); #define php_stream_stat(stream, ssb) _php_stream_stat((stream), (ssb) TSRMLS_CC) @@ -532,7 +537,7 @@ PHPAPI int php_unregister_url_stream_wrapper_volatile(char *protocol TSRMLS_DC); PHPAPI php_stream *_php_stream_open_wrapper_ex(char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC); PHPAPI php_stream_wrapper *php_stream_locate_url_wrapper(const char *path, char **path_for_open, int options TSRMLS_DC); -PHPAPI char *php_stream_locate_eol(php_stream *stream, char *buf, size_t buf_len TSRMLS_DC); +PHPAPI void *php_stream_locate_eol(php_stream *stream, zstr zbuf, int buf_len TSRMLS_DC); #define php_stream_open_wrapper(path, mode, options, opened) _php_stream_open_wrapper_ex((path), (mode), (options), (opened), NULL STREAMS_CC TSRMLS_CC) #define php_stream_open_wrapper_ex(path, mode, options, opened, context) _php_stream_open_wrapper_ex((path), (mode), (options), (opened), (context) STREAMS_CC TSRMLS_CC) http://cvs.php.net/viewcvs.cgi/php-src/main/streams/streams.c?r1=1.98&r2=1.99&diff_format=u Index: php-src/main/streams/streams.c diff -u php-src/main/streams/streams.c:1.98 php-src/main/streams/streams.c:1.99 --- php-src/main/streams/streams.c:1.98 Tue Feb 28 18:00:03 2006 +++ php-src/main/streams/streams.c Mon Mar 13 04:40:11 2006 @@ -19,7 +19,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: streams.c,v 1.98 2006/02/28 18:00:03 helly Exp $ */ +/* $Id: streams.c,v 1.99 2006/03/13 04:40:11 pollita Exp $ */ #define _GNU_SOURCE #include "php.h" @@ -368,11 +368,9 @@ stream->wrapperdata = NULL; } - while (stream->readbuf.head) { - php_stream_bucket *bucket = stream->readbuf.head; - - php_stream_bucket_unlink(bucket TSRMLS_CC); - php_stream_bucket_delref(bucket TSRMLS_CC); + if (stream->readbuf.v) { + pefree(stream->readbuf.v, stream->is_persistent); + stream->readbuf.v = NULL; } if (stream->is_persistent && (close_options & PHP_STREAM_FREE_PERSISTENT)) { @@ -422,8 +420,12 @@ /* {{{ generic stream operations */ +/* size == full characters (char, UChar, or 2x UChar) + TODO: Needs better handling of surrogate pairs */ static void php_stream_fill_read_buffer(php_stream *stream, size_t size TSRMLS_DC) { + /* allocate/fill the buffer */ + if (stream->readfilters.head) { char *chunk_buf; int err_flag = 0; @@ -433,7 +435,7 @@ /* allocate a buffer for reading chunks */ chunk_buf = emalloc(stream->chunk_size); - while (!err_flag && (stream->readbuf_avail < (off_t)size)) { + while (!err_flag && (stream->writepos - stream->readpos < (off_t)size)) { size_t justread = 0; int flags; php_stream_bucket *bucket; @@ -475,37 +477,28 @@ /* we get here when the last filter in the chain has data to pass on. * in this situation, we are passing the brig_in brigade into the * stream read buffer */ - while ((bucket = brig_inp->head)) { - php_stream_bucket *tail = stream->readbuf.tail; - php_stream_bucket_unlink(bucket TSRMLS_CC); - if (bucket->is_unicode && - U16_IS_SURROGATE(*bucket->buf.ustr.val) && - !U16_IS_SURROGATE_LEAD(*bucket->buf.ustr.val) && - tail && tail->is_unicode && - U16_IS_SURROGATE(tail->buf.ustr.val[tail->buf.ustr.len - 1]) && - U16_IS_SURROGATE_LEAD(tail->buf.ustr.val[tail->buf.ustr.len - 1])) { - /* Surrogate pair got split between buckets -- Unlikely */ - UChar *tmp; - - tmp = peumalloc(bucket->buf.ustr.len + 1, bucket->is_persistent); - *tmp = stream->readbuf.tail->buf.ustr.val[--tail->buf.ustr.len]; - memmove(tmp + UBYTES(1), bucket->buf.ustr.val, UBYTES(bucket->buf.ustr.len)); - pefree(bucket->buf.ustr.val, bucket->is_persistent); - bucket->buf.ustr.val = tmp; - - if (tail->buf.ustr.len <= 0) { - /* Tail was only a one UChar bucket */ - php_stream_bucket_unlink(tail TSRMLS_CC); - php_stream_bucket_delref(tail TSRMLS_CC); - } else if (tail == stream->readbuf.head && (tail->buf.ustr.len <= stream->readbuf_ofs)) { - /* Tail was head and last char was only unused portion */ - php_stream_bucket_unlink(tail TSRMLS_CC); - php_stream_bucket_delref(tail TSRMLS_CC); - stream->readbuf_ofs = 0; - } + while (brig_inp->head) { + bucket = brig_inp->head; + if (bucket->buf_type != IS_UNICODE && stream->input_encoding) { + /* Stream expects unicode, convert using stream encoding */ + php_stream_bucket_convert(bucket, IS_UNICODE, stream->input_encoding); + } else if (bucket->buf_type == IS_UNICODE && !stream->input_encoding) { + /* Stream expects binary, filter provided unicode, just take the buffer as is */ + php_stream_bucket_convert_notranscode(bucket, IS_STRING); + } + /* Bucket type now matches stream type */ + + /* grow buffer to hold this bucket + * TODO: this can fail for persistent streams */ + if (stream->readbuflen - stream->writepos < bucket->buflen) { + stream->readbuflen += bucket->buflen; + stream->readbuf.v = perealloc(stream->readbuf.v, PS_ULEN(stream->input_encoding, stream->readbuflen), stream->is_persistent); } - php_stream_bucket_append(&stream->readbuf, bucket TSRMLS_CC); - stream->readbuf_avail += bucket->is_unicode ? bucket->buf.ustr.len : bucket->buf.str.len; + memcpy(stream->readbuf.s + stream->writepos, bucket->buf.s, PS_ULEN(stream->input_encoding, bucket->buflen)); + stream->writepos += bucket->buflen; + + php_stream_bucket_unlink(bucket TSRMLS_CC); + php_stream_bucket_delref(bucket TSRMLS_CC); } break; @@ -533,58 +526,102 @@ } efree(chunk_buf); - - } else { + } else if (stream->input_encoding) { /* Unfiltered Unicode stream */ /* is there enough data in the buffer ? */ - if (stream->readbuf_avail < (off_t)size) { - char *chunk_buf; + if (stream->writepos - stream->readpos < (off_t)size) { + char *binbuf; + UChar *ubuf; + int binbuf_len, ubuf_len; + size_t toread = (size > stream->chunk_size) ? size : stream->chunk_size; + UErrorCode status = U_ZERO_ERROR; + + /* Read stream data into temporary buffer, then convert to unicode + TODO: This can be improved */ + binbuf = emalloc(toread + 1); + binbuf_len = stream->ops->read(stream, binbuf, toread TSRMLS_CC); + if (binbuf_len == (size_t)-1) { + /* Failure */ + efree(binbuf); + return; + } + /* Convert to unicode */ + zend_convert_to_unicode(stream->input_encoding, &ubuf, &ubuf_len, binbuf, binbuf_len, &status); + efree(binbuf); + + /* reduce buffer memory consumption if possible, to avoid a realloc */ + if (stream->readbuf.u && stream->readbuflen - stream->writepos < stream->chunk_size) { + memmove(stream->readbuf.u, stream->readbuf.u + stream->readpos, UBYTES(stream->readbuflen - stream->readpos)); + stream->writepos -= stream->readpos; + stream->readpos = 0; + } + + /* grow the buffer if required + * TODO: this can fail for persistent streams */ + if (stream->readbuflen - stream->writepos < ubuf_len) { + stream->readbuflen += ((stream->chunk_size > ubuf_len) ? stream->chunk_size : ubuf_len); + stream->readbuf.u = (UChar*)perealloc(stream->readbuf.u, UBYTES(stream->readbuflen), stream->is_persistent); + } + + memcpy(stream->readbuf.u + stream->writepos, ubuf, UBYTES(ubuf_len)); + efree(ubuf); + stream->writepos += ubuf_len; + } + } else { /* Unfiltered Binary stream */ + /* is there enough data in the buffer ? */ + if (stream->writepos - stream->readpos < (off_t)size) { size_t justread = 0; - int is_persistent = php_stream_is_persistent(stream); - chunk_buf = pemalloc(stream->chunk_size, is_persistent); - justread = stream->ops->read(stream, chunk_buf, stream->chunk_size TSRMLS_CC); + /* reduce buffer memory consumption if possible, to avoid a realloc */ + if (stream->readbuf.s && stream->readbuflen - stream->writepos < stream->chunk_size) { + memmove(stream->readbuf.s, stream->readbuf.s + stream->readpos, stream->readbuflen - stream->readpos); + stream->writepos -= stream->readpos; + stream->readpos = 0; + } - if (justread == (size_t)-1 || justread == 0) { - pefree(chunk_buf, is_persistent); - } else { - php_stream_bucket *bucket; + /* grow the buffer if required + * TODO: this can fail for persistent streams */ + if (stream->readbuflen - stream->writepos < stream->chunk_size) { + stream->readbuflen += stream->chunk_size; + stream->readbuf.s = (char*)perealloc(stream->readbuf.s, stream->readbuflen, stream->is_persistent); + } - bucket = php_stream_bucket_new(stream, chunk_buf, justread, 1, is_persistent TSRMLS_CC); - php_stream_bucket_append(&stream->readbuf, bucket TSRMLS_CC); - stream->readbuf_avail += justread; + justread = stream->ops->read(stream, stream->readbuf.s + stream->writepos, stream->readbuflen - stream->writepos TSRMLS_CC); + if (justread != (size_t)-1 && justread != 0) { + stream->writepos += justread; } } } } +/* Reads binary data from stream, if the stream is unicode (text), the raw unicode data will be returned */ PHPAPI size_t _php_stream_read(php_stream *stream, char *buf, size_t size TSRMLS_DC) { - php_stream_bucket *bucket; size_t toread = 0, didread = 0; while (size > 0) { + /* take from the read buffer first. * It is possible that a buffered stream was switched to non-buffered, so we * drain the remainder of the buffer before using the "raw" read mode for * the excess */ + if (stream->writepos - stream->readpos > 0) { + toread = UBYTES(stream->writepos - stream->readpos); - while (size > 0 && (bucket = stream->readbuf.head)) { - if (bucket->is_unicode) { - /* This is an string read func, convert to string first */ - php_stream_bucket_tostring(stream, &bucket, &stream->readbuf_ofs TSRMLS_CC); - } - toread = bucket->buf.str.len - stream->readbuf_ofs; if (toread > size) { toread = size; } - memcpy(buf, bucket->buf.str.val + stream->readbuf_ofs, toread); - stream->readbuf_ofs += toread; - stream->readbuf_avail -= toread; - if (stream->readbuf_ofs >= bucket->buf.str.len) { - php_stream_bucket_unlink(bucket TSRMLS_CC); - php_stream_bucket_delref(bucket TSRMLS_CC); - stream->readbuf_ofs = 0; + + if (stream->input_encoding) { + /* Sloppy read, anyone using php_stream_read() on a unicode stream + * had better know what they're doing */ + + memcpy(buf, stream->readbuf.u + stream->readpos, toread); + stream->readpos += ceil(toread / UBYTES(1)); + } else { + memcpy(buf, stream->readbuf.s + stream->readpos, toread); + stream->readpos += toread; } + size -= toread; buf += toread; didread += toread; @@ -595,39 +632,58 @@ break; } - /* just break anyway, to avoid greedy read */ - if (didread > 0 && (stream->wrapper != &php_plain_files_wrapper)) { - break; - } - if (!stream->readfilters.head && (stream->flags & PHP_STREAM_FLAG_NO_BUFFER || stream->chunk_size == 1)) { toread = stream->ops->read(stream, buf, size TSRMLS_CC); - if (toread <= 0) { - break; + } else { + php_stream_fill_read_buffer(stream, size TSRMLS_CC); + + toread = stream->writepos - stream->readpos; + if (toread > size) { + toread = size; + } + + if (toread > 0) { + if (php_stream_reads_unicode(stream)) { + /* Sloppy read, anyone using php_stream_read() on a unicode stream + * had better know what they're doing */ + + memcpy(buf, stream->readbuf.u + stream->readpos, toread); + stream->readpos += ceil(toread / UBYTES(1)); + } else { + memcpy(buf, stream->readbuf.s + stream->readpos, toread); + } + stream->readpos += toread; } + } + if (toread > 0) { + didread += toread; buf += toread; size -= toread; - didread += toread; - continue; - } - - php_stream_fill_read_buffer(stream, size TSRMLS_CC); - if (stream->readbuf_avail <= 0) { + } else { /* EOF, or temporary end of data (for non-blocking mode). */ break; } + /* just break anyway, to avoid greedy read */ + if (stream->wrapper != &php_plain_files_wrapper) { + break; + } } if (didread > 0) { stream->position += didread; } + return didread; } -PHPAPI size_t _php_stream_read_unicode(php_stream *stream, UChar *buf, int32_t size TSRMLS_DC) +/* Read unicode data from a stream. Returns failure (-1) if not a unicode stream */ +PHPAPI size_t _php_stream_read_unicode(php_stream *stream, UChar *buf, int size, int maxchars TSRMLS_DC) { - php_stream_bucket *bucket; - size_t toread = 0, didread = 0; + size_t toread = 0, didread = 0, string_length = 0; + + if (!stream->input_encoding) { + return -1; + } while (size > 0) { /* take from the read buffer first. @@ -635,32 +691,38 @@ * drain the remainder of the buffer before using the "raw" read mode for * the excess */ - while (size > 0 && (bucket = stream->readbuf.head)) { - UChar lastchar = 0; + while (size > 0 && (toread = (stream->writepos - stream->readpos)) && + (toread > 1 || + !U16_IS_SURROGATE(stream->readbuf.u[stream->readpos]) || + !U16_IS_SURROGATE_LEAD(stream->readbuf.u[stream->readpos]) )) { + int length; - if (!bucket->is_unicode) { - /* This is a unicode read func, convert to unicode first */ - php_stream_bucket_tounicode(stream, &bucket, &stream->readbuf_ofs TSRMLS_CC); - } - toread = bucket->buf.ustr.len - stream->readbuf_ofs; if (toread > size) { toread = size; } - lastchar = *(bucket->buf.ustr.val + stream->readbuf_ofs + toread - 1); - if (U16_IS_SURROGATE(lastchar) && U16_IS_SURROGATE_LEAD(lastchar)) { + + if (U16_IS_SURROGATE(stream->readbuf.u[stream->readpos + toread - 1]) && + U16_IS_SURROGATE_LEAD(stream->readbuf.u[stream->readpos + toread - 1])) { + /* Don't split surrogates */ toread--; - /* The only time we should encounter a split surrogate is when the buffer size is truncating the data - In this case, reduce size along with toread to avoid getting stuck */ - size--; - } - memcpy(buf, bucket->buf.ustr.val + stream->readbuf_ofs, toread * sizeof(UChar)); - stream->readbuf_ofs += toread; - stream->readbuf_avail -= toread; - if (stream->readbuf_ofs >= bucket->buf.ustr.len) { - php_stream_bucket_unlink(bucket TSRMLS_CC); - php_stream_bucket_delref(bucket TSRMLS_CC); - stream->readbuf_ofs = 0; + if (!toread) { + break; + } } + + if (maxchars > -1) { + length = u_countChar32(stream->readbuf.u + stream->readpos, toread); + if (string_length + length > maxchars) { + /* Don't read more U32 points than the caller asked for */ + toread = 0; + length = size - string_length; + U16_FWD_N(stream->readbuf.u + stream->readpos, toread, stream->writepos - stream->readpos, length); + } + string_length += length; + } + + memcpy(buf, stream->readbuf.u + stream->readpos, UBYTES(toread)); + stream->readpos += toread; size -= toread; buf += toread; didread += toread; @@ -677,7 +739,7 @@ } php_stream_fill_read_buffer(stream, size * sizeof(UChar) TSRMLS_CC); - if (stream->readbuf_avail <= 0) { + if (stream->writepos - stream->readpos <= 0) { /* EOF, or temporary end of data (for non-blocking mode). */ break; } @@ -690,184 +752,99 @@ return didread; } -/* buf mabe NULL (in which case it will be allocated) - num_bytes and num_chars must be initialized upon entry to maximum for each (-1 for no maximum) - num_bytes/num_chars will be set on exit to actual contents of buf - Will return unicode/string type dependent on the first character unit in the read buf - Will return as many characters as possible (and permitted by max lengths) without changing unicode/string type - Will not split surrogate pairs */ -PHPAPI void *_php_stream_u_read(php_stream *stream, void *buf, int32_t *pnum_bytes, int32_t *pnum_chars, int *pis_unicode TSRMLS_DC) +PHPAPI UChar *_php_stream_read_unicode_chars(php_stream *stream, int *pchars TSRMLS_DC) { - int grow_mode = 0; - int32_t num_bytes = 0, num_chars = 0; - int32_t max_bytes = *pnum_bytes, max_chars = *pnum_chars; - int32_t buflen = buf ? max_bytes : 2048; - int32_t bufpos = 0; - int is_unicode; - php_stream_bucket *bucket; - - /* It's possible that we have a readbuf, but that it's only half of a surrogate pair */ - if (!stream->readbuf.head || - (stream->readbuf.head == stream->readbuf.tail && stream->readbuf.head->is_unicode && - (stream->readbuf.head->buf.ustr.len - stream->readbuf_ofs) == 1 && - U16_IS_SURROGATE(stream->readbuf.head->buf.ustr.val[stream->readbuf.head->buf.ustr.len-1]))) { - php_stream_fill_read_buffer(stream, max_bytes ? max_bytes : (max_chars ? max_chars : stream->chunk_size) TSRMLS_CC); - } - + int size = *pchars; + UChar *bufstart, *buf; + int buflen = size; + size_t toread = 0, didread = 0, string_length = 0; - if (!stream->readbuf.head || - (stream->readbuf.head == stream->readbuf.tail && stream->readbuf.head->is_unicode && - (stream->readbuf.head->buf.ustr.len - stream->readbuf_ofs) == 1 && - U16_IS_SURROGATE(stream->readbuf.head->buf.ustr.val[stream->readbuf.head->buf.ustr.len-1]))) { - /* Nothing to return */ - *pnum_bytes = 0; - *pnum_chars = 0; - *pis_unicode = 0; + if (!stream->input_encoding) { return NULL; } + /* Allocate for ideal size first, add more later if needed */ + bufstart = buf = eumalloc(buflen + 1); - if (!buf) { - grow_mode = 1; - buf = emalloc(buflen); - } - - is_unicode = stream->readbuf.head->is_unicode; - if (is_unicode) { - /* normalize byte boundary */ - if (max_bytes >= 0 && (max_bytes % sizeof(UChar))) { - max_bytes -= (max_bytes % sizeof(UChar)); - } - if (max_bytes >= 0 && max_bytes < UBYTES(max_chars)) { - /* max_bytes needs to be at least twice max_chars when both are provided */ - max_chars = (max_bytes / sizeof(UChar)); - } - } else { - if (max_chars < 0 && max_bytes >= 0) { - max_chars = max_bytes; - } else if (max_chars >= 0 && grow_mode) { - max_bytes = max_chars; - } - } + while (size > 0) { + /* take from the read buffer first. + * It is possible that a buffered stream was switched to non-buffered, so we + * drain the remainder of the buffer before using the "raw" read mode for + * the excess */ - for (;;) { - if (buflen - bufpos < 1024 && max_bytes >= 0 && max_bytes > buflen) { - buflen += 1024; - if (buflen > max_bytes) { - buflen = max_bytes; - } - buf = erealloc(buf, buflen); - } + while (size > 0 && (toread = (stream->writepos - stream->readpos)) && + (toread > 1 || + !U16_IS_SURROGATE(stream->readbuf.u[stream->readpos]) || + !U16_IS_SURROGATE_LEAD(stream->readbuf.u[stream->readpos]) )) { + int length; - if ((bucket = stream->readbuf.head)) { - if ((bucket->is_unicode && !is_unicode) || - (!bucket->is_unicode && is_unicode)) { - /* data type swap, exit now */ - break; + if (toread > size) { + toread = size; } - if (bucket->is_unicode) { - UChar *s = bucket->buf.ustr.val + stream->readbuf_ofs, *p; - int bytes_in_buf, chars_in_buf; - int32_t ofs = 0; - - chars_in_buf = u_countChar32(s, bucket->buf.ustr.len - stream->readbuf_ofs); - if (chars_in_buf > max_chars && max_chars >= 0) { - chars_in_buf = max_chars; - } - /* u_countChar32 tells us that we won't overrun anyway */ - U16_FWD_N_UNSAFE(s, ofs, chars_in_buf); - p = s + ofs; - bytes_in_buf = UBYTES(ofs); - if (bytes_in_buf > (max_bytes - num_bytes)) { - bytes_in_buf = max_bytes - num_bytes; - bytes_in_buf -= bytes_in_buf & 1; /* normalize */ - p = s + (bytes_in_buf >> 1); - if (p > s && U16_IS_SURROGATE(p[-1]) && U16_IS_SURROGATE_LEAD(p[-1])) { - /* Don't split surrogate pairs */ - p--; - bytes_in_buf -= UBYTES(1); - } - if (bytes_in_buf <= 0) { - /* No room to copy data (surrogate pair) */ - break; - } - chars_in_buf = u_countChar32(s, p - s); - } - memcpy((char *)buf + num_bytes, s, bytes_in_buf); - num_bytes += bytes_in_buf; - num_chars += chars_in_buf; - stream->readbuf_ofs += p - s; - stream->readbuf_avail -= p - s; - if (stream->readbuf_ofs >= bucket->buf.ustr.len) { - php_stream_bucket_unlink(bucket TSRMLS_CC); - php_stream_bucket_delref(bucket TSRMLS_CC); - stream->readbuf_ofs = 0; - } else if (stream->readbuf_ofs == (bucket->buf.ustr.len - 1) && - U16_IS_SURROGATE(bucket->buf.ustr.val[bucket->buf.ustr.len - 1]) && - bucket->next && bucket->next->is_unicode) { - /* Only one char left in the bucket, avoid already split surrogates getting "stuck" -- Should never happen thanks to fill_read_buffer */ - php_stream_bucket *next_bucket = bucket->next; - - bucket->buf.ustr.val = peurealloc(bucket->buf.ustr.val, next_bucket->buf.ustr.len + 1, bucket->is_persistent); - bucket->buf.ustr.val[0] = bucket->buf.ustr.val[bucket->buf.ustr.len - 1]; - memcpy(bucket->buf.ustr.val + 1, next_bucket->buf.ustr.val, UBYTES(next_bucket->buf.ustr.len)); - php_stream_bucket_unlink(next_bucket TSRMLS_CC); - php_stream_bucket_delref(next_bucket TSRMLS_CC); - stream->readbuf_ofs = 0; - } else { - /* Reached max limits */ + if (U16_IS_SURROGATE(stream->readbuf.u[stream->readpos + toread - 1]) && + U16_IS_SURROGATE_LEAD(stream->readbuf.u[stream->readpos + toread - 1])) { + /* Don't split surrogates */ + toread--; + if (!toread) { break; } - } else { - int want = (max_chars < 0 || max_chars >= buflen) ? (buflen - num_bytes) : (max_chars - num_chars); - int avail = bucket->buf.str.len - stream->readbuf_ofs; + } - if (max_bytes >= 0 && want > max_bytes) { - want = max_bytes; - } + length = u_countChar32(stream->readbuf.u + stream->readpos, toread); + if (string_length + length > size) { + /* Don't read more U32 points than the caller asked for */ + toread = 0; + length = size - string_length; + U16_FWD_N(stream->readbuf.u + stream->readpos, toread, stream->writepos - stream->readpos, length); + } + + if (toread > (buflen - didread)) { + /* We know we're in surrogated territory at this point, allocate aggressively */ + int ofs = buf - bufstart; + buflen += size * 2; + bufstart = eurealloc(bufstart, buflen + 1); + buf = bufstart + ofs; + } - if (want > avail) { - want = avail; - } + memcpy(buf, stream->readbuf.u + stream->readpos, UBYTES(toread)); + stream->readpos += toread; + size -= toread; + buf += toread; + didread += toread; + string_length += length; + } - memcpy((char *)buf + num_bytes, bucket->buf.str.val + stream->readbuf_ofs, want); - stream->readbuf_ofs += want; - stream->readbuf_avail -= want; - num_bytes += want; - num_chars += want; - if (stream->readbuf_ofs >= bucket->buf.str.len) { - php_stream_bucket_unlink(bucket TSRMLS_CC); - php_stream_bucket_delref(bucket TSRMLS_CC); - stream->readbuf_ofs = 0; - } else { - /* Reached max limit */ - break; - } - } - } else { - /* No more data */ + /* ignore eof here; the underlying state might have changed */ + if (size == 0) { + break; + } + + /* just break anyway, to avoid greedy read */ + if (didread > 0 && (stream->wrapper != &php_plain_files_wrapper)) { + break; + } + + php_stream_fill_read_buffer(stream, UBYTES(size) TSRMLS_CC); + if (stream->writepos - stream->readpos <= 0) { + /* EOF, or temporary end of data (for non-blocking mode). */ break; } } - /* Successful exit */ - *pnum_bytes = num_bytes; - *pnum_chars = num_chars; - *pis_unicode = is_unicode; - stream->position += num_bytes; - - if (num_chars == 0 && grow_mode) { - efree(buf); - buf = NULL; + if (didread > 0) { + stream->position += didread; } - return buf; + + *pchars = string_length; + buf[0] = 0; + return bufstart; } PHPAPI int _php_stream_eof(php_stream *stream TSRMLS_DC) { /* if there is data in the buffer, it's not EOF */ - if (stream->readbuf_avail > 0) { + if (stream->writepos - stream->readpos > 0) { return 0; } @@ -933,25 +910,28 @@ return (stream->ops->stat)(stream, ssb TSRMLS_CC); } -/* buf != NULL Still used by file() in ext/standard/file.c - buf == NULL semantics no longer supported */ -PHPAPI char *php_stream_locate_eol(php_stream *stream, char *buf, size_t buf_len TSRMLS_DC) +PHPAPI void *php_stream_locate_eol(php_stream *stream, zstr zbuf, int buf_len TSRMLS_DC) { size_t avail; char *cr, *lf, *eol = NULL; - char *readptr; + char *readptr, *buf = zbuf.s; if (!buf) { - return NULL; + readptr = stream->readbuf.s + PS_ULEN(stream->input_encoding, stream->readpos); + avail = stream->writepos - stream->readpos; } else { - readptr = buf; + readptr = zbuf.s; avail = buf_len; - } + } - /* Look for EOL */ if (stream->flags & PHP_STREAM_FLAG_DETECT_EOL) { - cr = memchr(readptr, '\r', avail); - lf = memchr(readptr, '\n', avail); + if (stream->input_encoding) { + cr = (char*)u_memchr((UChar*)readptr, '\r', avail); + lf = (char*)u_memchr((UChar*)readptr, '\n', avail); + } else { + cr = memchr(readptr, '\r', avail); + lf = memchr(readptr, '\n', avail); + } if (cr && lf != cr + 1 && !(lf && lf < cr)) { /* mac */ @@ -964,377 +944,144 @@ eol = lf; } } else if (stream->flags & PHP_STREAM_FLAG_EOL_MAC) { - eol = memchr(readptr, '\r', avail); + eol = stream->input_encoding ? u_memchr((UChar*)readptr, '\r', avail) : memchr(readptr, '\r', avail); } else { /* unix (and dos) line endings */ - eol = memchr(readptr, '\n', avail); + eol = stream->input_encoding ? u_memchr((UChar*)readptr, '\n', avail) : memchr(readptr, '\n', avail); } - return eol; + return (void*)eol; } /* If buf == NULL, the buffer will be allocated automatically and will be of an * appropriate length to hold the line, regardless of the line length, memory - * permitting -- returned string will be up to (maxlen-1), last byte holding terminating NULL */ + * permitting -- returned string will be up to (maxlen-1), last byte holding terminating NULL + * Like php_stream_read(), this will treat unicode streams as ugly binary data (use with caution) */ PHPAPI char *_php_stream_get_line(php_stream *stream, char *buf, size_t maxlen, size_t *returned_len TSRMLS_DC) { - php_stream_bucket *bucket; + size_t avail = 0; + size_t current_buf_size = 0; size_t total_copied = 0; - int growmode = 0; - - if (!buf) { - maxlen = stream->chunk_size + 1; - buf = emalloc(maxlen); - growmode = 1; - } - - /* Leave room for NULL */ - maxlen--; - - for(;;) { - /* Fill buf with buffered data - until no space is left in the buffer - or EOL is found */ - char lastchar = 0; + int grow_mode = 0; + char *bufstart = buf; - /* consumed readbuf if possible */ - while ((bucket = stream->readbuf.head)) { - char *eol; - size_t tocopy; - size_t wanted = maxlen - total_copied; - int bucket_consumed = 0; - - if (bucket->is_unicode) { - /* This is a string read func, convert to string first */ - php_stream_bucket_tostring(stream, &bucket, &stream->readbuf_ofs TSRMLS_CC); - } - - if (stream->flags & PHP_STREAM_FLAG_DETECT_EOL && lastchar == '\r') { - /* Line ending was actually found in the last char of the last bucket - Since it was \r it could have been MAC or DOS */ - stream->flags ^= PHP_STREAM_FLAG_DETECT_EOL; - if (bucket->buf.str.val[stream->readbuf_ofs] == '\n') { - /* First byte here is a \n, put them together and you get DOS line endings */ - stream->readbuf_ofs++; - stream->readbuf_avail--; - buf[total_copied++] = '\n'; - /* unlikely -- It'd mean a one byte bucket -- possible though */ - if (stream->readbuf_ofs >= bucket->buf.str.len) { - stream->readbuf_ofs = 0; - php_stream_bucket_unlink(bucket TSRMLS_CC); - php_stream_bucket_delref(bucket TSRMLS_CC); - } - } else { - /* Seeing no \n in the first char of this bucket, we know it was MAC */ - stream->flags |= PHP_STREAM_FLAG_EOL_MAC; - } - goto exit_getline; - } else if (stream->flags & PHP_STREAM_FLAG_DETECT_EOL) { - char *cr, *lf; - lf = memchr(bucket->buf.str.val + stream->readbuf_ofs, '\n', bucket->buf.str.len - stream->readbuf_ofs); - cr = memchr(bucket->buf.str.val + stream->readbuf_ofs, '\r', bucket->buf.str.len - stream->readbuf_ofs); - eol = (cr && (!lf || cr < (lf - 1))) ? cr : lf; - } else if (stream->flags & PHP_STREAM_FLAG_EOL_MAC) { - eol = memchr(bucket->buf.str.val + stream->readbuf_ofs, '\r', bucket->buf.str.len - stream->readbuf_ofs); - } else { - eol = memchr(bucket->buf.str.val + stream->readbuf_ofs, '\n', bucket->buf.str.len - stream->readbuf_ofs); - } + if (buf == NULL) { + grow_mode = 1; + } else if (maxlen == 0) { + return NULL; + } - /* No \r or \n found in bucket -- grab it all */ - if (!eol) { - eol = bucket->buf.str.val + bucket->buf.str.len - 1; - } - tocopy = eol - (bucket->buf.str.val + stream->readbuf_ofs) + 1; + /* + * If the underlying stream operations block when no new data is readable, + * we need to take extra precautions. + * + * If there is buffered data available, we check for a EOL. If it exists, + * we pass the data immediately back to the caller. This saves a call + * to the read implementation and will not block where blocking + * is not necessary at all. + * + * If the stream buffer contains more data than the caller requested, + * we can also avoid that costly step and simply return that data. + */ - /* maxlen exceeded */ - if (tocopy > wanted && growmode) { - if (tocopy - wanted > stream->chunk_size) { - maxlen += tocopy - wanted; - } else { - maxlen += stream->chunk_size; - } - buf = erealloc(buf, maxlen + 1); - wanted = maxlen - total_copied; - } + for (;;) { + avail = stream->writepos - stream->readpos; - if (tocopy > wanted) { - tocopy = wanted; - } + if (avail > 0) { + size_t cpysz = 0; + char *readptr; + char *eol; + int done = 0; - memcpy(buf + total_copied, bucket->buf.str.val + stream->readbuf_ofs, tocopy); - total_copied += tocopy; - stream->readbuf_ofs += tocopy; - stream->readbuf_avail -= tocopy; - lastchar = buf[total_copied-1]; + readptr = stream->readbuf.s + stream->readpos; + eol = php_stream_locate_eol(stream, (zstr)NULL, 0 TSRMLS_CC); - if (stream->readbuf_ofs >= bucket->buf.str.len) { - stream->readbuf_ofs = 0; - php_stream_bucket_unlink(bucket TSRMLS_CC); - php_stream_bucket_delref(bucket TSRMLS_CC); - bucket_consumed = 1; + if (eol) { + cpysz = eol - readptr + 1; + done = 1; + } else { + cpysz = avail; } - if (total_copied >= maxlen) { - goto exit_getline; + if (grow_mode) { + /* allow room for a NUL. If this realloc is really a realloc + * (ie: second time around), we get an extra byte. In most + * cases, with the default chunk size of 8K, we will only + * incur that overhead once. When people have lines longer + * than 8K, we waste 1 byte per additional 8K or so. + * That seems acceptable to me, to avoid making this code + * hard to follow */ + bufstart = erealloc(bufstart, current_buf_size + cpysz + 1); + current_buf_size += cpysz + 1; + buf = bufstart + total_copied; + } else { + if (cpysz >= maxlen - 1) { + cpysz = maxlen - 1; + done = 1; + } } - if (stream->flags & PHP_STREAM_FLAG_DETECT_EOL && - bucket_consumed && lastchar == '\r') { - /* Could be MAC, could be DOS... - Need to check the first char of the next bucket to be sure */ - continue; - } + memcpy(buf, readptr, cpysz); - if (lastchar == '\r' || lastchar == '\n') { - stream->flags ^= PHP_STREAM_FLAG_DETECT_EOL; - if (lastchar == '\r') { - /* if there were a \n in this bucket after the \r, we would be looking at it */ - stream->flags |= PHP_STREAM_FLAG_EOL_MAC; - } - goto exit_getline; - } - } + stream->position += cpysz; + stream->readpos += cpysz; + buf += cpysz; + maxlen -= cpysz; + total_copied += cpysz; - if (stream->eof) { - if (total_copied == 0) { - if (growmode) { - efree(buf); + if (done) { + break; + } + } else if (stream->eof) { + break; + } else { + /* XXX: Should be fine to always read chunk_size */ + size_t toread; + + if (grow_mode) { + toread = stream->chunk_size; + } else { + toread = maxlen - 1; + if (toread > stream->chunk_size) { + toread = stream->chunk_size; } - return NULL; } - goto exit_getline; - } - if (maxlen - total_copied) { - size_t bufneeded = maxlen - total_copied; + php_stream_fill_read_buffer(stream, toread TSRMLS_CC); - if (growmode) { - bufneeded = stream->chunk_size; + if (stream->writepos - stream->readpos == 0) { + break; } - php_stream_fill_read_buffer(stream, bufneeded TSRMLS_CC); } - } - exit_getline: + if (total_copied == 0) { + if (grow_mode) { + assert(bufstart == NULL); + } + return NULL; + } + buf[0] = '\0'; if (returned_len) { *returned_len = total_copied; } - buf[total_copied] = 0; - stream->position += total_copied; - return buf; + return bufstart; } -/* If buf == NULL, the buffer will be allocated automatically and will be of an - * appropriate length to hold the line, regardless of the line length, memory - * permitting -- returned string will be up to (maxlen-1), last byte holding terminating NULL */ PHPAPI UChar *_php_stream_u_get_line(php_stream *stream, UChar *buf, int32_t *pmax_bytes, int32_t *pmax_chars, int *pis_unicode TSRMLS_DC) { - php_stream_bucket *bucket; - int32_t num_bytes = 0, num_chars = 0; - int32_t max_bytes = *pmax_bytes, max_chars = *pmax_chars; - int growmode = 0, is_unicode; - - while (!stream->readbuf.head) { - /* Nothing buffered, get an idea of the data type by polling */ - int32_t fillsize = (max_chars > 0) ? max_chars : ((max_bytes > 0) ? max_bytes : stream->chunk_size); - - php_stream_fill_read_buffer(stream, fillsize TSRMLS_CC); - if (!stream->readbuf.head) { - *pmax_bytes = 0; - *pmax_chars = 0; - *pis_unicode = 0; - return NULL; - } - } - - *pis_unicode = is_unicode = stream->readbuf.head->is_unicode; - - if (!is_unicode) { - /* Wrap normal get_line() */ - int returned_len; - char *retbuf = php_stream_get_line(stream, (char*)buf, max_chars, &returned_len); - - *pmax_chars = returned_len; - *pmax_bytes = returned_len; - return (UChar*)retbuf; - } - - /* Now act like php_stream_u_read(), but stopping at 000A, 000D, or 000D 000A */ - - if (!buf) { - max_bytes = UBYTES(257); - buf = emalloc(max_bytes); - growmode = 1; - } - - /* Leave room for NULL */ - max_bytes -= UBYTES(1); - - for(;;) { - /* Fill buf with buffered data - until no space is left in the buffer - or EOL is found */ - UChar lastchar = 0; - - /* consumed readbuf if possible */ - while ((bucket = stream->readbuf.head)) { - UChar *eol, *s; - int32_t want_chars = max_chars - num_chars; - int32_t want_bytes = max_bytes - num_bytes; - int32_t count_chars; - int32_t count_bytes; - int bucket_consumed = 0; - - if (!bucket->is_unicode) { - /* Done with unicode data, bail as though EOL was reached (even though it wasn't) */ - goto exit_ugetline; - } - - if (stream->flags & PHP_STREAM_FLAG_DETECT_EOL && lastchar == '\r') { - /* Line ending was actually found in the last char of the last bucket - Since it was \r it could have been MAC or DOS */ - stream->flags ^= PHP_STREAM_FLAG_DETECT_EOL; - if (bucket->buf.ustr.val[stream->readbuf_ofs] == '\n') { - /* First byte here is a \n, put them together and you get DOS line endings */ - stream->readbuf_ofs++; - stream->readbuf_avail--; - buf[num_bytes >> 1] = '\n'; /* Can't use num_chars here, surrogate pairs will foul it up */ - num_bytes += UBYTES(1); - num_chars++; - /* unlikely -- It'd mean a one UChar bucket -- possible though */ - if (stream->readbuf_ofs >= bucket->buf.ustr.len) { - stream->readbuf_ofs = 0; - php_stream_bucket_unlink(bucket TSRMLS_CC); - php_stream_bucket_delref(bucket TSRMLS_CC); - } - } else { - /* Seeing no \n in the first char of this bucket, we know it was MAC */ - stream->flags |= PHP_STREAM_FLAG_EOL_MAC; - } - goto exit_ugetline; - } else if (stream->flags & PHP_STREAM_FLAG_DETECT_EOL) { - UChar *cr, *lf; - lf = u_memchr(bucket->buf.ustr.val + stream->readbuf_ofs, '\n', bucket->buf.ustr.len - stream->readbuf_ofs); - cr = u_memchr(bucket->buf.ustr.val + stream->readbuf_ofs, '\r', bucket->buf.ustr.len - stream->readbuf_ofs); - eol = (cr && (!lf || cr < (lf - 1))) ? cr : lf; - } else if (stream->flags & PHP_STREAM_FLAG_EOL_MAC) { - eol = u_memchr(bucket->buf.ustr.val + stream->readbuf_ofs, '\r', bucket->buf.ustr.len - stream->readbuf_ofs); - } else { - eol = u_memchr(bucket->buf.ustr.val + stream->readbuf_ofs, '\n', bucket->buf.ustr.len - stream->readbuf_ofs); - } - - /* No \r or \n found in bucket -- grab it all */ - if (!eol) { - eol = bucket->buf.ustr.val + bucket->buf.ustr.len - 1; - } - s = bucket->buf.ustr.val + stream->readbuf_ofs; - - count_bytes = UBYTES(eol - s + 1); - if (count_bytes > want_bytes && growmode) { - max_bytes = num_bytes + count_bytes + UBYTES(256); - want_bytes = max_bytes - num_bytes; - buf = erealloc(buf, max_bytes + UBYTES(1)); - } else if (count_bytes > want_bytes) { - count_bytes = want_bytes; - } - if (U16_IS_SURROGATE(s[(count_bytes >> 1) - 1]) && - U16_IS_SURROGATE_LEAD(s[(count_bytes >> 1) - 1])) { - count_bytes -= UBYTES(1); - } - if (count_bytes <= 0) { - /* Not enough space in buffer, just break out */ - goto exit_ugetline; - } - count_chars = u_countChar32(s, count_bytes >> 1); - - if (max_chars >= 0 && count_chars > want_chars) { - count_chars = want_chars; - count_bytes = 0; - U16_FWD_N_UNSAFE(s, count_bytes, count_chars); - count_bytes <<= 1; /* translate U16 to bytes */ - } - - memcpy(buf + (num_bytes >> 1), s, count_bytes); - num_bytes += count_bytes; - num_chars += count_chars; - stream->readbuf_ofs += count_bytes >> 1; - stream->readbuf_avail -= count_bytes >> 1; - - lastchar = buf[(num_bytes >> 1) - 1]; - - if (stream->readbuf_ofs >= bucket->buf.ustr.len) { - stream->readbuf_ofs = 0; - php_stream_bucket_unlink(bucket TSRMLS_CC); - php_stream_bucket_delref(bucket TSRMLS_CC); - bucket_consumed = 1; - } - - if ((max_bytes >= 0 && num_bytes >= max_bytes) || - (max_chars >= 0 && num_chars >= max_chars)) { - goto exit_ugetline; - } - - if (stream->flags & PHP_STREAM_FLAG_DETECT_EOL && - bucket_consumed && lastchar == '\r') { - /* Could be MAC, could be DOS... - Need to check the first char of the next bucket to be sure */ - continue; - } - - if (lastchar == '\r' || lastchar == '\n') { - stream->flags ^= PHP_STREAM_FLAG_DETECT_EOL; - if (lastchar == '\r') { - /* if there were a \n in this bucket after the \r, we would be looking at it */ - stream->flags |= PHP_STREAM_FLAG_EOL_MAC; - } - goto exit_ugetline; - } - } - - if (stream->eof) { - if (num_bytes == 0) { - if (growmode) { - efree(buf); - } - buf = NULL; - } - goto exit_ugetline; - } - - if (max_bytes - num_bytes) { - int32_t want_bytes = max_bytes - num_bytes; - - if (growmode) { - want_bytes = stream->chunk_size; - } - php_stream_fill_read_buffer(stream, want_bytes TSRMLS_CC); - } - - } - - exit_ugetline: + /* TODO: Bring this back up to date */ - *pmax_chars = num_chars; - *pmax_bytes = num_bytes; - *pis_unicode = is_unicode; - if (buf) { - buf[num_bytes >> 1] = 0; - } - stream->position += num_bytes; - - return buf; + return NULL; } +/* Same deal as php_stream_read() and php_stream_get_line() + * Will give unexpected results if used against a unicode stream */ PHPAPI char *php_stream_get_record(php_stream *stream, size_t maxlen, size_t *returned_len, char *delim, size_t delim_len TSRMLS_DC) { - /* UTODO: Needs desperate rewriting for unicode conversion */ - return NULL; - -#ifdef SMG_0 char *e, *buf; size_t toread; int skip = 0; @@ -1345,15 +1092,15 @@ toread = maxlen; } else { if (delim_len == 1) { - e = memchr(stream->readbuf, *delim, stream->readbuf_len); + e = memchr(stream->readbuf.s + stream->readpos, *delim, stream->writepos - stream->readpos); } else { - e = php_memnstr(stream->readbuf, delim, delim_len, (stream->readbuf + stream->readbuflen)); + e = php_memnstr(stream->readbuf.s + stream->readpos, delim, delim_len, (stream->readbuf.s + stream->writepos)); } if (!e) { toread = maxlen; } else { - toread = e - (char *) stream->readbuf; + toread = e - stream->readbuf.s - stream->readpos; skip = 1; } } @@ -1376,49 +1123,48 @@ efree(buf); return NULL; } -#endif -} - -PHPAPI void _php_stream_flush_readbuf(php_stream *stream TSRMLS_DC) -{ - php_stream_bucket *bucket; - - while ((bucket = stream->readbuf.head)) { - php_stream_bucket_unlink(bucket TSRMLS_CC); - php_stream_bucket_delref(bucket TSRMLS_CC); - } - stream->readbuf_ofs = stream->readbuf_avail = 0; } /* Writes a buffer directly to a stream, using multiple of the chunk size */ -static size_t _php_stream_write_buffer(php_stream *stream, const char *buf, size_t count TSRMLS_DC) +static size_t _php_stream_write_buffer(php_stream *stream, int buf_type, zstr buf, int buflen TSRMLS_DC) { size_t didwrite = 0, towrite, justwrote; + char *freeme = NULL; /* if we have a seekable stream we need to ensure that data is written at the * current stream->position. This means invalidating the read buffer and then * performing a low-level seek */ -/* UTODO: FIX this if (stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0 && stream->readpos != stream->writepos) { -*/ - if (stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0) { - php_stream_flush_readbuf(stream); + stream->readpos = stream->writepos = 0; stream->ops->seek(stream, stream->position, SEEK_SET, &stream->position TSRMLS_CC); } - - while (count > 0) { - towrite = count; - if (towrite > stream->chunk_size) + if (stream->output_encoding) { + char *dest; + int destlen; + UErrorCode status = U_ZERO_ERROR; + + zend_convert_from_unicode(stream->output_encoding, &dest, &destlen, buf.u, buflen, &status); + freeme = buf.s = dest; + buflen = destlen; + } else { + /* Sloppy handling, make it a binary buffer */ + buflen = UBYTES(buflen); + } + + while (buflen > 0) { + towrite = buflen; + if (towrite > stream->chunk_size) { towrite = stream->chunk_size; + } - justwrote = stream->ops->write(stream, buf, towrite TSRMLS_CC); + justwrote = stream->ops->write(stream, buf.s, towrite TSRMLS_CC); /* convert justwrote to an integer, since normally it is unsigned */ if ((int)justwrote > 0) { - buf += justwrote; - count -= justwrote; + buf.s += justwrote; + buflen -= justwrote; didwrite += justwrote; /* Only screw with the buffer if we can seek, otherwise we lose data @@ -1430,8 +1176,12 @@ break; } } - return didwrite; + if (freeme) { + efree(freeme); + } + + return didwrite; } /* push some data through the write filter chain. @@ -1439,7 +1189,7 @@ * This may trigger a real write to the stream. * Returns the number of bytes consumed from buf by the first filter in the chain. * */ -static size_t _php_stream_write_filtered(php_stream *stream, const char *buf, size_t count, int flags, int is_unicode TSRMLS_DC) +static size_t _php_stream_write_filtered(php_stream *stream, int buf_type, zstr buf, int count, int flags TSRMLS_DC) { size_t consumed = 0; php_stream_bucket *bucket; @@ -1448,11 +1198,11 @@ php_stream_filter_status_t status = PSFS_ERR_FATAL; php_stream_filter *filter; - if (buf) { - if (is_unicode) { - bucket = php_stream_bucket_new_unicode(stream, (UChar *)buf, count, 0, 0 TSRMLS_CC); + if (buf.v) { + if (buf_type == IS_UNICODE) { + bucket = php_stream_bucket_new_unicode(stream, buf.u, count, 0, 0 TSRMLS_CC); } else { - bucket = php_stream_bucket_new(stream, (char *)buf, count, 0, 0 TSRMLS_CC); + bucket = php_stream_bucket_new(stream, buf.s, count, 0, 0 TSRMLS_CC); } php_stream_bucket_append(brig_inp, bucket TSRMLS_CC); } @@ -1479,11 +1229,7 @@ * underlying stream */ while (brig_inp->head) { bucket = brig_inp->head; - if (bucket->is_unicode) { - _php_stream_write_buffer(stream, (char *)bucket->buf.ustr.val, UBYTES(bucket->buf.ustr.len) TSRMLS_CC); - } else { - _php_stream_write_buffer(stream, bucket->buf.str.val, bucket->buf.str.len TSRMLS_CC); - } + _php_stream_write_buffer(stream, bucket->buf_type, bucket->buf, bucket->buflen TSRMLS_CC); /* Potential error situation - eg: no space on device. Perhaps we should keep this brigade * hanging around and try to write it later. * At the moment, we just drop it on the floor @@ -1506,53 +1252,12 @@ return consumed; } -PHPAPI int _php_stream_will_read_unicode(php_stream *stream TSRMLS_DC) -{ - php_stream_filter *filter; - int inverted = 0; - - if (stream->readbuf.head) { - /* If there are buckets available, what do they hold */ - return stream->readbuf.head->is_unicode; - } - - if (!stream->readfilters.head) { - /* Not filtered == reads as string */ - return 0; - } - - for(filter = stream->readfilters.tail; filter; filter = filter->prev) { - if (filter->flags & PSFO_FLAG_OUTPUTS_SAME) { - continue; - } - if (filter->flags & PSFO_FLAG_OUTPUTS_OPPOSITE) { - inverted ^= 1; - continue; - } - if (filter->flags & PSFO_FLAG_OUTPUTS_ANY) { - /* Indeterminate */ - return -1; - } - if (filter->flags & PSFO_FLAG_OUTPUTS_STRING) { - /* If an inversion happens, it'll be unicode, otherwise string */ - return inverted; - } - if (filter->flags & PSFO_FLAG_OUTPUTS_UNICODE) { - /* If an inversion happens, it'll be string, otherwise unicode */ - return inverted ^ 1; - } - } - - /* string comes from stream so apply same logic as filter outputting string */ - return inverted; -} - PHPAPI int _php_stream_flush(php_stream *stream, int closing TSRMLS_DC) { int ret = 0; if (stream->writefilters.head) { - _php_stream_write_filtered(stream, NULL, 0, closing ? PSFS_FLAG_FLUSH_CLOSE : PSFS_FLAG_FLUSH_INC, 0 TSRMLS_CC); + _php_stream_write_filtered(stream, IS_STRING, (zstr)NULL, 0, closing ? PSFS_FLAG_FLUSH_CLOSE : PSFS_FLAG_FLUSH_INC TSRMLS_CC); } if (stream->ops->flush) { @@ -1569,13 +1274,13 @@ } if (stream->writefilters.head) { - return _php_stream_write_filtered(stream, buf, count, PSFS_FLAG_NORMAL, 0 TSRMLS_CC); + return _php_stream_write_filtered(stream, IS_STRING, (zstr)((char*)buf), count, PSFS_FLAG_NORMAL TSRMLS_CC); } else { - return _php_stream_write_buffer(stream, buf, count TSRMLS_CC); + return _php_stream_write_buffer(stream, IS_STRING, (zstr)((char*)buf), count TSRMLS_CC); } } -PHPAPI size_t _php_stream_u_write(php_stream *stream, const UChar *buf, int32_t count TSRMLS_DC) +PHPAPI size_t _php_stream_write_unicode(php_stream *stream, const UChar *buf, int count TSRMLS_DC) { int32_t ret; @@ -1584,9 +1289,9 @@ } if (stream->writefilters.head) { - ret = _php_stream_write_filtered(stream, (const char*)buf, count, PSFS_FLAG_NORMAL, 1 TSRMLS_CC); + ret = _php_stream_write_filtered(stream, IS_UNICODE, (zstr)((UChar*)buf), count, PSFS_FLAG_NORMAL TSRMLS_CC); } else { - ret = _php_stream_write_buffer(stream, (const char*)buf, UBYTES(count) TSRMLS_CC); + ret = _php_stream_write_buffer(stream, IS_UNICODE, (zstr)((UChar*)buf), count TSRMLS_CC); } /* Return data points, not bytes */ @@ -1626,48 +1331,22 @@ /* handle the case where we are in the buffer */ if ((stream->flags & PHP_STREAM_FLAG_NO_BUFFER) == 0) { switch(whence) { - case SEEK_SET: - if (offset < stream->position || - offset > stream->position + stream->readbuf_avail) { - break; - } - /* act like SEEK_CUR */ - whence = SEEK_CUR; - offset -= stream->position; - /* fall through */ case SEEK_CUR: - if (offset == 0) { - /* nothing to do */ - return stream->position >= 0 ? 0 : -1; - } - - if (offset > 0 && offset <= stream->readbuf_avail) { - php_stream_bucket *bucket; - - while (offset && (bucket = stream->readbuf.head)) { - int consume = bucket->buf.str.len - stream->readbuf_ofs; - - if (consume > offset) { - /* seeking within this bucket */ - stream->readbuf_ofs += offset; - stream->readbuf_avail -= offset; - stream->position += offset; - break; - } - - /* consume the remaining bucket */ - stream->position += consume; - stream->readbuf_ofs = 0; - stream->readbuf_avail -= consume; - offset -= consume; - - php_stream_bucket_unlink(bucket TSRMLS_CC); - php_stream_bucket_delref(bucket TSRMLS_CC); - } + if (offset > 0 && offset < stream->writepos - stream->readpos) { + stream->readpos += offset; + stream->position += offset; stream->eof = 0; return 0; } break; + case SEEK_SET: + if (offset > stream->position && + offset < stream->position + stream->writepos - stream->readpos) { + stream->readpos += offset - stream->position; + stream->position = offset; + stream->eof = 0; + return 0; + } } } @@ -1678,7 +1357,7 @@ if (stream->writefilters.head) { _php_stream_flush(stream, 0 TSRMLS_CC); } - + switch(whence) { case SEEK_CUR: offset = stream->position + offset; @@ -1693,7 +1372,7 @@ } /* invalidate the buffer contents */ - php_stream_flush_readbuf(stream); + stream->readpos = stream->writepos = 0; return ret; } @@ -2445,41 +2124,15 @@ /* Output encoding on text mode streams defaults to utf8 unless specified in context parameter */ if (stream && strchr(implicit_mode, 't') && UG(unicode)) { if (strchr(implicit_mode, 'w') || strchr(implicit_mode, 'a') || strchr(implicit_mode, '+')) { - php_stream_filter *filter; char *encoding = (context && context->output_encoding) ? context->output_encoding : "utf8"; - char *filtername; - int encoding_len = strlen(encoding); + UErrorCode status = U_ZERO_ERROR; - filtername = emalloc(encoding_len + sizeof("unicode.to.")); - memcpy(filtername, "unicode.to.", sizeof("unicode.to.") - 1); - memcpy(filtername + sizeof("unicode.to.") - 1, encoding, encoding_len + 1); - - filter = php_stream_filter_create(filtername, NULL, persistent TSRMLS_CC); - if (!filter) { - php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Failed applying output encoding"); - } else { - php_stream_filter_append(&stream->writefilters, filter); - } - efree(filtername); + stream->output_encoding = ucnv_open(encoding, &status); } - if (strchr(implicit_mode, 'r') || strchr(implicit_mode, '+')) { - php_stream_filter *filter; - char *filtername; char *encoding = (context && context->input_encoding) ? context->input_encoding : "utf8"; - int input_encoding_len = strlen(encoding); - - filtername = emalloc(input_encoding_len + sizeof("unicode.from.")); - memcpy(filtername, "unicode.from.", sizeof("unicode.from.") - 1); - memcpy(filtername + sizeof("unicode.from.") - 1, encoding, input_encoding_len + 1); - - filter = php_stream_filter_create(filtername, NULL, persistent TSRMLS_CC); - if (!filter) { - php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Failed applying input encoding"); - } else { - php_stream_filter_append(&stream->readfilters, filter); - } - efree(filtername); + UErrorCode status = U_ZERO_ERROR; + stream->input_encoding = ucnv_open(encoding, &status); } } @@ -2496,8 +2149,6 @@ pefree(copy_of_path, persistent); } #endif - - return stream; } /* }}} */ http://cvs.php.net/viewcvs.cgi/php-src/main/streams/filter.c?r1=1.22&r2=1.23&diff_format=u Index: php-src/main/streams/filter.c diff -u php-src/main/streams/filter.c:1.22 php-src/main/streams/filter.c:1.23 --- php-src/main/streams/filter.c:1.22 Thu Jan 12 19:21:36 2006 +++ php-src/main/streams/filter.c Mon Mar 13 04:40:11 2006 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: filter.c,v 1.22 2006/01/12 19:21:36 helly Exp $ */ +/* $Id: filter.c,v 1.23 2006/03/13 04:40:11 pollita Exp $ */ #include "php.h" #include "php_globals.h" @@ -85,22 +85,22 @@ if (is_persistent && !buf_persistent) { /* all data in a persistent bucket must also be persistent */ - bucket->buf.str.val = pemalloc(buflen, 1); + bucket->buf.s = pemalloc(buflen, 1); - if (bucket->buf.str.val == NULL) { + if (bucket->buf.s == NULL) { pefree(bucket, 1); return NULL; } - memcpy(bucket->buf.str.val, buf, buflen); - bucket->buf.str.len = buflen; + memcpy(bucket->buf.s, buf, buflen); + bucket->buflen = buflen; bucket->own_buf = 1; } else { - bucket->buf.str.val = buf; - bucket->buf.str.len = buflen; + bucket->buf.s = buf; + bucket->buflen = buflen; bucket->own_buf = own_buf; } - bucket->is_unicode = 0; + bucket->buf_type = IS_STRING; bucket->is_persistent = is_persistent; bucket->refcount = 1; @@ -122,22 +122,22 @@ if (is_persistent && !buf_persistent) { /* all data in a persistent bucket must also be persistent */ - bucket->buf.ustr.val = safe_pemalloc(sizeof(UChar), buflen, 0, 1); + bucket->buf.u = safe_pemalloc(sizeof(UChar), buflen, 0, 1); - if (bucket->buf.ustr.val == NULL) { + if (bucket->buf.u == NULL) { pefree(bucket, 1); return NULL; } - memcpy(bucket->buf.ustr.val, buf, buflen); - bucket->buf.ustr.len = buflen; + memcpy(bucket->buf.u, buf, buflen); + bucket->buflen = buflen; bucket->own_buf = 1; } else { - bucket->buf.ustr.val = buf; - bucket->buf.ustr.len = buflen; + bucket->buf.u = buf; + bucket->buflen = buflen; bucket->own_buf = own_buf; } - bucket->is_unicode = 1; + bucket->buf_type = IS_UNICODE; bucket->is_persistent = is_persistent; bucket->refcount = 1; @@ -164,12 +164,12 @@ retval = (php_stream_bucket*)pemalloc(sizeof(php_stream_bucket), bucket->is_persistent); memcpy(retval, bucket, sizeof(*retval)); - if (bucket->is_unicode) { - retval->buf.ustr.val = safe_pemalloc(sizeof(UChar), retval->buf.ustr.len, 0, retval->is_persistent); - memcpy(retval->buf.ustr.val, bucket->buf.ustr.val, retval->buf.ustr.len * sizeof(UChar)); + if (bucket->buf_type == IS_UNICODE) { + retval->buf.u = safe_pemalloc(sizeof(UChar), retval->buflen, 0, retval->is_persistent); + memcpy(retval->buf.u, bucket->buf.u, UBYTES(retval->buflen)); } else { - retval->buf.str.val = pemalloc(retval->buf.str.len, retval->is_persistent); - memcpy(retval->buf.str.val, bucket->buf.str.val, retval->buf.str.len); + retval->buf.s = pemalloc(retval->buflen, retval->is_persistent); + memcpy(retval->buf.s, bucket->buf.s, retval->buflen); } retval->refcount = 1; @@ -189,58 +189,46 @@ goto exit_fail; } - if (in->is_unicode) { - (*left)->buf.ustr.val = safe_pemalloc(sizeof(UChar), length, 0, in->is_persistent); - (*left)->buf.ustr.len = length; - memcpy((*left)->buf.str.val, in->buf.str.val, length * sizeof(UChar)); - - (*right)->buf.ustr.len = in->buf.ustr.len - length; - (*right)->buf.ustr.val = pemalloc((*right)->buf.ustr.len, in->is_persistent); - memcpy((*right)->buf.ustr.val, in->buf.ustr.val + (length * sizeof(UChar)), (*right)->buf.str.len * sizeof(UChar)); - } else { - (*left)->buf.str.val = pemalloc(length, in->is_persistent); - (*left)->buf.str.len = length; - memcpy((*left)->buf.str.val, in->buf.str.val, length); - - (*right)->buf.str.len = in->buf.str.len - length; - (*right)->buf.str.val = pemalloc((*right)->buf.str.len, in->is_persistent); - memcpy((*right)->buf.str.val, in->buf.str.val + length, (*right)->buf.str.len); + if (in->buf_type == IS_UNICODE) { + (*left)->buf.u = safe_pemalloc(sizeof(UChar), length, 0, in->is_persistent); + (*left)->buflen = length; + memcpy((*left)->buf.u, in->buf.u, UBYTES(length)); + + (*right)->buflen = in->buflen - length; + (*right)->buf.u = pemalloc(UBYTES((*right)->buflen), in->is_persistent); + memcpy((*right)->buf.u, in->buf.u + length, UBYTES((*right)->buflen)); + } else { + (*left)->buf.s = pemalloc(length, in->is_persistent); + (*left)->buflen = length; + memcpy((*left)->buf.s, in->buf.s, length); + + (*right)->buflen = in->buflen - length; + (*right)->buf.s = pemalloc((*right)->buflen, in->is_persistent); + memcpy((*right)->buf.s, in->buf.s + length, (*right)->buflen); } (*left)->refcount = 1; (*left)->own_buf = 1; (*left)->is_persistent = in->is_persistent; - (*left)->is_unicode = in->is_unicode; + (*left)->buf_type = in->buf_type; (*right)->refcount = 1; (*right)->own_buf = 1; (*right)->is_persistent = in->is_persistent; - (*right)->is_unicode = in->is_unicode; + (*right)->buf_type = in->buf_type; return SUCCESS; exit_fail: if (*right) { - if ((*right)->is_unicode) { - if ((*right)->buf.ustr.val) { - pefree((*right)->buf.ustr.val, in->is_persistent); - } - } else { - if ((*right)->buf.str.val) { - pefree((*right)->buf.str.val, in->is_persistent); - } + if ((*right)->buf.v) { + pefree((*right)->buf.v, in->is_persistent); } pefree(*right, in->is_persistent); } if (*left) { - if ((*left)->is_unicode) { - if ((*left)->buf.ustr.val) { - pefree((*left)->buf.ustr.val, in->is_persistent); - } - } else { - if ((*left)->buf.str.val) { - pefree((*left)->buf.str.val, in->is_persistent); - } + if ((*left)->buf.v) { + pefree((*left)->buf.v, in->is_persistent); } pefree(*left, in->is_persistent); } @@ -251,7 +239,7 @@ { if (--bucket->refcount == 0) { if (bucket->own_buf) { - pefree(bucket->is_unicode ? (char*)bucket->buf.ustr.val : bucket->buf.str.val, bucket->is_persistent); + pefree(bucket->buf.v, bucket->is_persistent); } pefree(bucket, bucket->is_persistent); } @@ -408,30 +396,31 @@ chain->tail = filter; filter->chain = chain; - if (&(stream->readfilters) == chain && (stream->readbuf_avail) > 0) { + if (&(stream->readfilters) == chain && (stream->writepos - stream->readpos) > 0) { /* Let's going ahead and wind anything in the buffer through this filter */ - php_stream_bucket_brigade brig_out = { NULL, NULL }; - php_stream_bucket_brigade *brig_outp = &brig_out; + php_stream_bucket_brigade brig_in = { NULL, NULL }, brig_out = { NULL, NULL }; + php_stream_bucket_brigade *brig_inp = &brig_in, *brig_outp = &brig_out; php_stream_filter_status_t status; php_stream_bucket *bucket; + size_t consumed = 0; - if (stream->readbuf_ofs) { - /* Mask readbuf_ofs from filter */ - bucket = stream->readbuf.head; - if (bucket->is_unicode) { - bucket->buf.ustr.len -= stream->readbuf_ofs; - memmove(bucket->buf.ustr.val, bucket->buf.ustr.val + (stream->readbuf_ofs * sizeof(UChar)), bucket->buf.ustr.len * sizeof(UChar)); - } else { - bucket->buf.str.len -= stream->readbuf_ofs; - memmove(bucket->buf.str.val, bucket->buf.str.val + stream->readbuf_ofs, bucket->buf.str.len); - } + if (stream->input_encoding) { + bucket = php_stream_bucket_new_unicode(stream, stream->readbuf.u + stream->readpos, stream->writepos - stream->readpos, 0, 0 TSRMLS_CC); + } else { + bucket = php_stream_bucket_new(stream, stream->readbuf.s + stream->readpos, stream->writepos - stream->readpos, 0, 0 TSRMLS_CC); } + php_stream_bucket_append(brig_inp, bucket TSRMLS_CC); + status = filter->fops->filter(stream, filter, brig_inp, brig_outp, &consumed, PSFS_FLAG_NORMAL TSRMLS_CC); - status = filter->fops->filter(stream, filter, &stream->readbuf, brig_outp, NULL, PSFS_FLAG_NORMAL TSRMLS_CC); + if (stream->readpos + consumed > stream->writepos || consumed < 0) { + /* No behaving filter should cause this. */ + status = PSFS_ERR_FATAL; + } switch (status) { case PSFS_ERR_FATAL: - /* filter is fundamentally broken, invalidate readbuf and strip the filter */ + /* If this first cycle simply fails then there's something wrong with the filter. + Pull the filter off the chain and leave the read buffer alone. */ if (chain->head == filter) { chain->head = NULL; chain->tail = NULL; @@ -439,31 +428,61 @@ filter->prev->next = NULL; chain->tail = filter->prev; } - php_stream_flush_readbuf(stream); - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Filter failed to process pre-buffered data"); - /* Passthru -- Anything successfully filtered can go back on the readbuf */ - case PSFS_PASS_ON: - stream->readbuf_ofs = stream->readbuf_avail = 0; - - /* Merge brig_out */ - while((bucket = brig_out.head)) { - php_stream_bucket_unlink(bucket TSRMLS_CC); - php_stream_bucket_append(&stream->readbuf, bucket TSRMLS_CC); - } - - /* Count available bytes */ - for(bucket = stream->readbuf.head; bucket; bucket = bucket->next) { - stream->readbuf_avail += bucket->is_unicode ? bucket->buf.ustr.len : bucket->buf.str.len; - } + php_stream_bucket_unlink(bucket TSRMLS_CC); + php_stream_bucket_delref(bucket TSRMLS_CC); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Filter failed to process pre-buffered data. Not adding to filterchain."); break; case PSFS_FEED_ME: /* We don't actually need data yet, leave this filter in a feed me state until data is needed. Reset stream's internal read buffer since the filter is "holding" it. */ - stream->readbuf.head = stream->readbuf.tail = NULL; - stream->readbuf_avail = stream->readbuf_ofs = 0; + stream->readpos = 0; + stream->writepos = 0; + break; + case PSFS_PASS_ON: + /* Put any filtered data onto the readbuffer stack. + Previously read data has been at least partially consumed. */ + stream->readpos += consumed; + + if (stream->writepos == stream->readpos) { + /* Entirely consumed */ + stream->writepos = 0; + stream->readpos = 0; + } + + while (brig_outp->head) { + bucket = brig_outp->head; + + /* Convert for stream type */ + if (bucket->buf_type != IS_UNICODE && stream->input_encoding) { + /* Stream expects unicode, convert using stream encoding */ + php_stream_bucket_convert(bucket, IS_UNICODE, stream->input_encoding); + } else if (bucket->buf_type == IS_UNICODE && !stream->input_encoding) { + /* Stream expects binary, filter provided unicode, just take the buffer as is */ + php_stream_bucket_convert_notranscode(bucket, IS_STRING); + } + + /* Grow buffer to hold this bucket if need be. + TODO: See warning in main/stream/streams.c::php_stream_fill_read_buffer */ + if (stream->readbuflen - stream->writepos < bucket->buflen) { + stream->readbuflen += bucket->buflen; + stream->readbuf.v = perealloc(stream->readbuf.v, PS_ULEN(stream->input_encoding, stream->readbuflen), stream->is_persistent); + } + + /* Append to readbuf */ + if (stream->input_encoding) { + memcpy(stream->readbuf.u + stream->writepos, bucket->buf.u, UBYTES(bucket->buflen)); + } else { + memcpy(stream->readbuf.s + stream->writepos, bucket->buf.s, bucket->buflen); + } + stream->writepos += bucket->buflen; + + php_stream_bucket_unlink(bucket TSRMLS_CC); + php_stream_bucket_delref(bucket TSRMLS_CC); + } break; } + } } @@ -566,7 +585,7 @@ Do something with it */ for(bucket = inp->head; bucket; bucket = bucket->next) { - flushed_size += bucket->is_unicode ? bucket->buf.ustr.len : bucket->buf.str.len; + flushed_size += bucket->buflen; } if (flushed_size == 0) { @@ -575,33 +594,56 @@ } if (chain == &(stream->readfilters)) { - if (stream->readbuf.head) { - /* Merge inp with readbuf */ - for(bucket = inp->head; bucket; bucket = bucket->next) { - php_stream_bucket_unlink(bucket TSRMLS_CC); - php_stream_bucket_append(&stream->readbuf, bucket TSRMLS_CC); - stream->readbuf_avail += bucket->is_unicode ? bucket->buf.ustr.len : bucket->buf.str.len; + /* Dump any newly flushed data to the read buffer */ + if (stream->readpos > stream->chunk_size) { + /* Back the buffer up */ + memcpy(stream->readbuf.s, stream->readbuf.s + PS_ULEN(stream->input_encoding, stream->readpos), PS_ULEN(stream->input_encoding, stream->writepos - stream->readpos)); + stream->writepos -= stream->readpos; + stream->readpos = 0; + } + if (flushed_size > (stream->readbuflen - stream->writepos)) { + /* Grow the buffer */ + stream->readbuf.v = perealloc(stream->readbuf.v, PS_ULEN(stream->input_encoding, stream->writepos + flushed_size + stream->chunk_size), stream->is_persistent); + } + while ((bucket = inp->head)) { + /* Convert if necessary */ + if (bucket->buf_type != IS_UNICODE && stream->input_encoding) { + /* Stream expects unicode, convert using stream encoding */ + php_stream_bucket_convert(bucket, IS_UNICODE, stream->input_encoding); + } else if (bucket->buf_type == IS_UNICODE && !stream->input_encoding) { + /* Stream expects binary, filter provided unicode, just take the buffer as is */ + php_stream_bucket_convert_notranscode(bucket, IS_STRING); } - } else { - /* Just plop it in */ - stream->readbuf = *inp; - stream->readbuf_avail = flushed_size; - stream->readbuf_ofs = 0; + + /* Append to readbuf */ + if (stream->input_encoding) { + memcpy(stream->readbuf.u + stream->writepos, bucket->buf.u, UBYTES(bucket->buflen)); + } else { + memcpy(stream->readbuf.s + stream->writepos, bucket->buf.s, bucket->buflen); + } + stream->writepos += bucket->buflen; + php_stream_bucket_unlink(bucket TSRMLS_CC); + php_stream_bucket_delref(bucket TSRMLS_CC); } + + } else if (chain == &(stream->writefilters)) { /* Send flushed data to the stream */ while ((bucket = inp->head)) { - char *data; - int datalen; - - if (bucket->is_unicode) { - data = (char*)bucket->buf.ustr.val; - datalen = bucket->buf.ustr.len * sizeof(UChar); - } else { - data = bucket->buf.str.val; - datalen = bucket->buf.str.len; + /* Convert if necessary */ + if (bucket->buf_type == IS_UNICODE) { + if (stream->output_encoding) { + /* Stream has a configured output encoding, convert to appropriate type */ + php_stream_bucket_convert(bucket, IS_STRING, stream->output_encoding); + } else { + /* Stream is binary, write ugly UChars as is */ + php_stream_bucket_convert_notranscode(bucket, IS_STRING); + } } - stream->ops->write(stream, data, datalen TSRMLS_CC); + + /* Must be binary by this point */ + stream->ops->write(stream, bucket->buf.s, bucket->buflen TSRMLS_CC); + php_stream_bucket_unlink(bucket TSRMLS_CC); php_stream_bucket_delref(bucket TSRMLS_CC); } @@ -634,104 +676,93 @@ return filter; } -PHPAPI int php_stream_bucket_tounicode(php_stream *stream, php_stream_bucket **pbucket, off_t *offset TSRMLS_DC) +PHPAPI int _php_stream_bucket_convert(php_stream_bucket *bucket, unsigned char type, UConverter *conv TSRMLS_DC) { - int is_persistent = php_stream_is_persistent(stream); - php_stream_bucket *bucket = *pbucket, *prior = bucket->prev, *next = bucket->next; - php_stream_bucket_brigade *brigade = bucket->brigade; - UErrorCode status = U_ZERO_ERROR; - UChar *val; - int32_t len; - - if (bucket->is_unicode) { + if (bucket->buf_type == type) { return SUCCESS; } - zend_convert_to_unicode(ZEND_U_CONVERTER(UG(runtime_encoding_conv)), &val, &len, bucket->buf.str.val, bucket->buf.str.len, &status); + if (conv) { + /* transcode current type using provided converter */ + if (type == IS_UNICODE) { + UErrorCode status = U_ZERO_ERROR; + UChar *dest; + int destlen; - if (U_FAILURE(status)) { - efree(val); - return FAILURE; - } + zend_convert_to_unicode(conv, &dest, &destlen, bucket->buf.s, bucket->buflen, &status); - php_stream_bucket_unlink(bucket TSRMLS_CC); - php_stream_bucket_delref(bucket TSRMLS_CC); - - /* convert from unicode defaults to non-persistent */ - bucket = php_stream_bucket_new_unicode(stream, val, len, 1, is_persistent TSRMLS_CC); - if (is_persistent) { - efree(val); - } - - bucket->brigade = brigade; - bucket->prev = prior; - bucket->next = next; - - if (prior) { - prior->next = bucket; - } else if (brigade) { - brigade->head = bucket; - } - - if (next) { - next->prev = bucket; - } else if (brigade) { - brigade->tail = bucket; - } - - *pbucket = bucket; - - return SUCCESS; -} - -PHPAPI int php_stream_bucket_tostring(php_stream *stream, php_stream_bucket **pbucket, off_t *offset TSRMLS_DC) -{ - int is_persistent = php_stream_is_persistent(stream); - php_stream_bucket *bucket = *pbucket, *prior = bucket->prev, *next = bucket->next; - php_stream_bucket_brigade *brigade = bucket->brigade; - UErrorCode status = U_ZERO_ERROR; - char *val; - int len; - - if (!bucket->is_unicode) { - return SUCCESS; - } + if (bucket->own_buf) { + pefree(bucket->buf.s, bucket->is_persistent); + } - zend_convert_from_unicode(ZEND_U_CONVERTER(UG(runtime_encoding_conv)), &val, &len, bucket->buf.ustr.val, bucket->buf.ustr.len, &status); + /* Might be dangerous, double check this (or, better, get a persistent version of zend_convert_to_unicode() */ + bucket->is_persistent = 0; - if (U_FAILURE(status)) { - efree(val); - return FAILURE; - } + bucket->buf_type = IS_UNICODE; + bucket->buf.u = dest; + bucket->buflen = destlen; + bucket->own_buf = 1; + return SUCCESS; + } else { + UErrorCode status = U_ZERO_ERROR; + char *dest; + int destlen; - php_stream_bucket_unlink(bucket TSRMLS_CC); - php_stream_bucket_delref(bucket TSRMLS_CC); + zend_convert_from_unicode(conv, &dest, &destlen, bucket->buf.u, bucket->buflen, &status); - /* convert from unicode defaults to non-persistent */ - bucket = php_stream_bucket_new(stream, val, len, 1, is_persistent TSRMLS_CC); - if (is_persistent) { - efree(val); - } + if (bucket->own_buf) { + pefree(bucket->buf.u, bucket->is_persistent); + } - bucket->brigade = brigade; - bucket->prev = prior; - bucket->next = next; + /* See above */ + bucket->is_persistent = 0; - if (prior) { - prior->next = bucket; - } else if (brigade) { - brigade->head = bucket; - } + bucket->buf_type = IS_STRING; + bucket->buf.s = dest; + bucket->buflen = destlen; + bucket->own_buf = 1; + return SUCCESS; + } + } else { + /* Convert without transcode, usually a bad idea as it creates ugly data, + When binary streams receive unicode data (because of filters or writing unicode strings) + this is the only option */ + if (type == IS_UNICODE) { + if (bucket->buflen == 0) { + /* Shortcut conversion for empty buckets */ + if (bucket->own_buf) { + pefree(bucket->buf.s, bucket->is_persistent); + } + bucket->buf_type == IS_UNICODE; + bucket->buf.u = (UChar*)"\x00\x00"; + bucket->own_buf = 0; + bucket->buflen = 0; + return SUCCESS; + } - if (next) { - next->prev = bucket; - } else if (brigade) { - brigade->tail = bucket; + if (bucket->own_buf) { + /* one UChar padding for partial units, one more for terminating NULL */ + bucket->buf.s = perealloc(bucket->buf.s, bucket->buflen + UBYTES(2), bucket->is_persistent); + } else { + int destlen = ceil(bucket->buflen / sizeof(UChar)); + UChar *dest = pemalloc(UBYTES(destlen + 2), bucket->is_persistent); + memcpy(dest, bucket->buf.s, bucket->buflen); + bucket->buf.u = dest; + bucket->own_buf = 1; + } + memset(bucket->buf.s + bucket->buflen, 0, UBYTES(2)); + bucket->buf_type = IS_UNICODE; + bucket->buflen = ceil(bucket->buflen / sizeof(UChar)); + return SUCCESS; + } else { /* IS_STRING */ + bucket->buf_type = IS_STRING; + bucket->buflen *= 2; + return SUCCESS; + } } - *pbucket = bucket; - - return SUCCESS; + /* Never reached */ + return FAILURE; } /* http://cvs.php.net/viewcvs.cgi/php-src/main/streams/cast.c?r1=1.14&r2=1.15&diff_format=u Index: php-src/main/streams/cast.c diff -u php-src/main/streams/cast.c:1.14 php-src/main/streams/cast.c:1.15 --- php-src/main/streams/cast.c:1.14 Sun Jan 1 13:09:57 2006 +++ php-src/main/streams/cast.c Mon Mar 13 04:40:11 2006 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: cast.c,v 1.14 2006/01/01 13:09:57 sniper Exp $ */ +/* $Id: cast.c,v 1.15 2006/03/13 04:40:11 pollita Exp $ */ #define _GNU_SOURCE #include "php.h" @@ -150,8 +150,7 @@ off_t dummy; stream->ops->seek(stream, stream->position, SEEK_SET, &dummy TSRMLS_CC); - - php_stream_flush_readbuf(stream); + stream->readpos = stream->writepos = 0; } } @@ -259,7 +258,7 @@ exit_success: - if ((stream->readbuf_avail) > 0 && + if ((stream->writepos - stream->readpos) > 0 && stream->fclose_stdiocast != PHP_STREAM_FCLOSE_FOPENCOOKIE && (flags & PHP_STREAM_CAST_INTERNAL) == 0) { /* the data we have buffered will be lost to the third party library that @@ -268,7 +267,7 @@ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%ld bytes of buffered data lost during stream conversion!", - stream->readbuf_avail); + (long)(stream->writepos - stream->readpos)); } if (castas == PHP_STREAM_AS_STDIO && ret) http://cvs.php.net/viewcvs.cgi/php-src/main/streams/php_stream_filter_api.h?r1=1.15&r2=1.16&diff_format=u Index: php-src/main/streams/php_stream_filter_api.h diff -u php-src/main/streams/php_stream_filter_api.h:1.15 php-src/main/streams/php_stream_filter_api.h:1.16 --- php-src/main/streams/php_stream_filter_api.h:1.15 Sun Jan 1 13:09:57 2006 +++ php-src/main/streams/php_stream_filter_api.h Mon Mar 13 04:40:11 2006 @@ -19,7 +19,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_stream_filter_api.h,v 1.15 2006/01/01 13:09:57 sniper Exp $ */ +/* $Id: php_stream_filter_api.h,v 1.16 2006/03/13 04:40:11 pollita Exp $ */ /* The filter API works on the principle of "Bucket-Brigades". This is * partially inspired by the Apache 2 method of doing things, although @@ -45,21 +45,13 @@ php_stream_bucket *next, *prev; php_stream_bucket_brigade *brigade; - union { - struct { - char *val; - size_t len; - } str; - struct { - UChar *val; - int32_t len; - } ustr; - } buf; + zstr buf; + int buflen; /* Length in units (char or UChar) */ /* if non-zero, buf should be pefreed when the bucket is destroyed */ char own_buf; + char buf_type; /* IS_STRING or IS_UNICODE */ char is_persistent; - char is_unicode; /* destroy this struct when refcount falls to zero */ int refcount; @@ -86,9 +78,10 @@ PHPAPI void php_stream_bucket_append(php_stream_bucket_brigade *brigade, php_stream_bucket *bucket TSRMLS_DC); PHPAPI void php_stream_bucket_unlink(php_stream_bucket *bucket TSRMLS_DC); PHPAPI php_stream_bucket *php_stream_bucket_make_writeable(php_stream_bucket *bucket TSRMLS_DC); -PHPAPI int php_stream_bucket_tounicode(php_stream *stream, php_stream_bucket **pbucket, off_t *offset TSRMLS_DC); -PHPAPI int php_stream_bucket_tostring(php_stream *stream, php_stream_bucket **pbucket, off_t *offset TSRMLS_DC); +PHPAPI int _php_stream_bucket_convert(php_stream_bucket *bucket, unsigned char type, UConverter *conv TSRMLS_DC); END_EXTERN_C() +#define php_stream_bucket_convert(bucket, type, conv) _php_stream_bucket_convert((bucket), (type), (conv) TSRMLS_CC); +#define php_stream_bucket_convert_notranscode(bucket, type) _php_stream_bucket_convert((bucket), (type), NULL TSRMLS_CC); #define PSFS_FLAG_NORMAL 0 /* regular read/write */ #define PSFS_FLAG_FLUSH_INC 1 /* an incremental flush */ http://cvs.php.net/viewcvs.cgi/php-src/ext/standard/file.c?r1=1.423&r2=1.424&diff_format=u Index: php-src/ext/standard/file.c diff -u php-src/ext/standard/file.c:1.423 php-src/ext/standard/file.c:1.424 --- php-src/ext/standard/file.c:1.423 Wed Mar 8 00:43:28 2006 +++ php-src/ext/standard/file.c Mon Mar 13 04:40:11 2006 @@ -21,7 +21,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: file.c,v 1.423 2006/03/08 00:43:28 pajoye Exp $ */ +/* $Id: file.c,v 1.424 2006/03/13 04:40:11 pollita Exp $ */ /* Synced with php 3.0 revision 1.218 1999-06-16 [ssb] */ @@ -507,7 +507,7 @@ char *contents; zend_bool use_include_path = 0; php_stream *stream; - int len, newlen; + int len; long offset = -1; long maxlen = PHP_STREAM_COPY_ALL; zval *zcontext = NULL; @@ -555,7 +555,7 @@ char *filename; int filename_len; zval *data; - int numbytes = 0; + int numchars = 0; long flags = 0; zval *zcontext = NULL; php_stream_context *context = NULL; @@ -592,36 +592,36 @@ php_stream *srcstream; php_stream_from_zval(srcstream, &data); - numbytes = php_stream_copy_to_stream(srcstream, stream, PHP_STREAM_COPY_ALL); + numchars = php_stream_copy_to_stream(srcstream, stream, PHP_STREAM_COPY_ALL); break; } case IS_ARRAY: if (zend_hash_num_elements(Z_ARRVAL_P(data))) { - int bytes_written; zval **tmp; HashPosition pos; zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(data), &pos); while (zend_hash_get_current_data_ex(Z_ARRVAL_P(data), (void **) &tmp, &pos) == SUCCESS) { if (Z_TYPE_PP(tmp) == IS_UNICODE) { - int wrote_bytes = php_stream_u_write(stream, Z_USTRVAL_PP(tmp), Z_USTRLEN_PP(tmp)); - if (wrote_bytes < 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to write %d characters to %s", Z_USTRLEN_PP(tmp), filename); - numbytes = -1; + int ustrlen = u_countChar32(Z_USTRVAL_PP(tmp), Z_USTRLEN_PP(tmp)); + int wrote_u16 = php_stream_write_unicode(stream, Z_USTRVAL_PP(tmp), Z_USTRLEN_PP(tmp)); + if (wrote_u16 < 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to write %d characters to %s", ustrlen, filename); + numchars = -1; break; - } else if (wrote_bytes != UBYTES(Z_USTRLEN_PP(tmp))) { - int ustrlen = u_countChar32(Z_USTRVAL_PP(tmp), Z_USTRLEN_PP(tmp)); - int numchars = u_countChar32(Z_USTRVAL_PP(tmp), wrote_bytes / UBYTES(1)); + } else if (wrote_u16 != Z_USTRLEN_PP(tmp)) { + int numchars = u_countChar32(Z_USTRVAL_PP(tmp), wrote_u16); php_error_docref(NULL TSRMLS_CC, E_WARNING, "Only %d of %d characters written, possibly out of free disk space", numchars, ustrlen); - numbytes = -1; + numchars = -1; break; } - numbytes += wrote_bytes; + numchars += ustrlen; } else { /* non-unicode */ int free_val = 0; zval strval = **tmp; + int wrote_bytes; if (Z_TYPE(strval) != IS_STRING) { zval_copy_ctor(&strval); @@ -629,15 +629,16 @@ free_val = 1; } if (Z_STRLEN(strval)) { - numbytes += Z_STRLEN(strval); - bytes_written = php_stream_write(stream, Z_STRVAL(strval), Z_STRLEN(strval)); - if (bytes_written < 0 || bytes_written != Z_STRLEN(strval)) { - if (bytes_written < 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to write %d bytes to %s", Z_STRLEN(strval), filename); - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Only %d of %d bytes written, possibly out of free disk space", bytes_written, Z_STRLEN(strval)); - } - numbytes = -1; + numchars += Z_STRLEN(strval); + wrote_bytes = php_stream_write(stream, Z_STRVAL(strval), Z_STRLEN(strval)); + if (wrote_bytes < 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to write %d bytes to %s", Z_STRLEN(strval), filename); + numchars = -1; + break; + } + if (wrote_bytes != Z_STRLEN(strval)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Only %d of %d bytes written, possibly out of free disk space", wrote_bytes, Z_STRLEN(strval)); + numchars = -1; break; } } @@ -652,20 +653,20 @@ case IS_OBJECT: /* TODO */ php_error_docref(NULL TSRMLS_CC, E_WARNING, "2nd parameter must be non-object (for now)"); - numbytes = -1; + numchars = -1; break; case IS_UNICODE: if (Z_USTRLEN_P(data)) { - numbytes = php_stream_u_write(stream, Z_USTRVAL_P(data), Z_USTRLEN_P(data)); - if (numbytes < 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to write %d characters to %s", Z_USTRLEN_P(data), filename); - numbytes = -1; - } else if (numbytes != UBYTES(Z_USTRLEN_P(data))) { - int ustrlen = u_countChar32(Z_USTRVAL_P(data), Z_USTRLEN_P(data)); - int numchars = u_countChar32(Z_USTRVAL_P(data), numbytes / UBYTES(1)); + int ustrlen = u_countChar32(Z_USTRVAL_P(data), Z_USTRLEN_P(data)); + numchars = php_stream_write_unicode(stream, Z_USTRVAL_P(data), Z_USTRLEN_P(data)); + if (numchars < 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to write %d characters to %s", ustrlen, filename); + numchars = -1; + } else if (numchars != UBYTES(Z_USTRLEN_P(data))) { + int numchars = u_countChar32(Z_USTRVAL_P(data), numchars); php_error_docref(NULL TSRMLS_CC, E_WARNING, "Only %d of %d characters written, possibly out of free disk space", numchars, ustrlen); - numbytes = -1; + numchars = -1; } } break; @@ -680,10 +681,10 @@ convert_to_string_ex(&data); } if (Z_STRLEN_P(data)) { - numbytes = php_stream_write(stream, Z_STRVAL_P(data), Z_STRLEN_P(data)); - if (numbytes != Z_STRLEN_P(data)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Only %d of %d bytes written, possibly out of free disk space", numbytes, Z_STRLEN_P(data)); - numbytes = -1; + numchars = php_stream_write(stream, Z_STRVAL_P(data), Z_STRLEN_P(data)); + if (numchars != Z_STRLEN_P(data)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Only %d of %d bytes written, possibly out of free disk space", numchars, Z_STRLEN_P(data)); + numchars = -1; } } break; @@ -691,11 +692,11 @@ } php_stream_close(stream); - if (numbytes < 0) { + if (numchars < 0) { RETURN_FALSE; } - RETURN_LONG(numbytes); + RETURN_LONG(numchars); } /* }}} */ @@ -709,9 +710,9 @@ { char *filename; int filename_len; - char *slashed, *target_buf=NULL, *p, *s, *e; + char *target_buf=NULL, *p, *s, *e; register int i = 0; - int target_len, len; + int target_len; char eol_marker = '\n'; long flags = 0; zend_bool use_include_path; @@ -748,7 +749,7 @@ s = target_buf; e = target_buf + target_len; - if (!(p = php_stream_locate_eol(stream, target_buf, target_len TSRMLS_CC))) { + if (!(p = php_stream_locate_eol(stream, (zstr)target_buf, target_len TSRMLS_CC))) { p = e; goto parse_eol; } @@ -1024,10 +1025,7 @@ PHPAPI PHP_FUNCTION(fgetc) { zval **arg1; - char buf[2 * sizeof(UChar)]; - int is_unicode; php_stream *stream; - int32_t num_bytes = UBYTES(2), num_chars = 1; if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg1) == FAILURE) { WRONG_PARAM_COUNT; @@ -1035,18 +1033,20 @@ PHP_STREAM_TO_ZVAL(stream, arg1); - if (!php_stream_u_read(stream, buf, &num_bytes, &num_chars, &is_unicode)) { - RETVAL_FALSE; - } else { - if (is_unicode) { - UChar *ubuf = (UChar *)buf; - int num_u16 = num_bytes >> 1; - ubuf[num_u16] = 0; - RETURN_UNICODEL(ubuf, num_u16, 1); - } else { - buf[1] = 0; - RETURN_STRINGL(buf, 1, 1); + if (php_stream_reads_unicode(stream)) { + int buflen = 1; + UChar *buf = php_stream_read_unicode_chars(stream, &buflen); + + if (!buf) { + RETURN_FALSE; } + RETURN_UNICODEL(buf, buflen, 0); + } else { + char buf[2]; + + buf[0] = php_stream_getc(stream); + buf[1] = 0; + RETURN_STRINGL(buf, 1, 1); } } /* }}} */ @@ -1213,26 +1213,19 @@ if (write_len < 0 || write_len > Z_USTRLEN_P(zstring)) { write_len = Z_USTRLEN_P(zstring); } - ret = php_stream_u_write(stream, Z_USTRVAL_P(zstring), write_len); + ret = php_stream_write_unicode(stream, Z_USTRVAL_P(zstring), write_len); /* Convert data points back to code units */ if (ret > 0) { ret = u_countChar32(Z_USTRVAL_P(zstring), ret); } } else { - char *buffer = NULL; - int num_bytes; - convert_to_string(zstring); if (write_len < 0 || write_len > Z_STRLEN_P(zstring)) { write_len = Z_STRLEN_P(zstring); } - num_bytes = write_len; - ret = php_stream_write(stream, buffer ? buffer : Z_STRVAL_P(zstring), num_bytes); - if (buffer) { - efree(buffer); - } + ret = php_stream_write(stream, Z_STRVAL_P(zstring), write_len); } RETURN_LONG(ret); @@ -1759,11 +1752,8 @@ PHPAPI PHP_FUNCTION(fread) { zval *zstream; - char *buf; long len; php_stream *stream; - int is_unicode; - int32_t num_bytes, num_chars; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &zstream, &len) == FAILURE) { RETURN_NULL(); @@ -1776,22 +1766,25 @@ RETURN_FALSE; } - num_chars = len; - num_bytes = UBYTES(len); - buf = emalloc(num_bytes + UBYTES(1)); + if (php_stream_reads_unicode(stream)) { + int buflen = len; + UChar *buf = php_stream_read_unicode_chars(stream, &buflen); - if (!php_stream_u_read(stream, buf, &num_bytes, &num_chars, &is_unicode)) { - efree(buf); - RETURN_FALSE; - } + if (!buf) { + RETURN_FALSE; + } - if (is_unicode) { - buf[num_bytes] = 0; - buf[num_bytes + 1] = 0; - RETURN_UNICODEL((UChar *)buf, num_bytes >> 1, 0); + RETURN_UNICODEL(buf, buflen, 0); } else { - buf[num_bytes] = 0; - RETURN_STRINGL(buf, num_bytes, 0); + char *buf = emalloc(len + 1); + int buflen = php_stream_read(stream, buf, len); + + if (!buflen) { + efree(buf); + RETURN_FALSE; + } + buf[buflen] = 0; + RETURN_STRINGL(buf, buflen, 0); } } /* }}} */ http://cvs.php.net/viewcvs.cgi/php-src/ext/standard/user_filters.c?r1=1.36&r2=1.37&diff_format=u Index: php-src/ext/standard/user_filters.c diff -u php-src/ext/standard/user_filters.c:1.36 php-src/ext/standard/user_filters.c:1.37 --- php-src/ext/standard/user_filters.c:1.36 Thu Mar 2 13:12:45 2006 +++ php-src/ext/standard/user_filters.c Mon Mar 13 04:40:11 2006 @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: user_filters.c,v 1.36 2006/03/02 13:12:45 dmitry Exp $ */ +/* $Id: user_filters.c,v 1.37 2006/03/13 04:40:11 pollita Exp $ */ #include "php.h" #include "php_globals.h" @@ -376,12 +376,12 @@ add_property_zval(return_value, "bucket", zbucket); /* add_property_zval increments the refcount which is unwanted here */ zval_ptr_dtor(&zbucket); - if (bucket->is_unicode) { - add_property_unicodel(return_value, "data", bucket->buf.ustr.val, bucket->buf.ustr.len, 1); - add_property_long(return_value, "datalen", bucket->buf.ustr.len); + if (bucket->buf_type == IS_UNICODE) { + add_property_unicodel(return_value, "data", bucket->buf.u, bucket->buflen, 1); + add_property_long(return_value, "datalen", bucket->buflen); } else { - add_property_stringl(return_value, "data", bucket->buf.str.val, bucket->buf.str.len, 1); - add_property_long(return_value, "datalen", bucket->buf.str.len); + add_property_stringl(return_value, "data", bucket->buf.s, bucket->buflen, 1); + add_property_long(return_value, "datalen", bucket->buflen); } } } @@ -412,34 +412,34 @@ bucket = php_stream_bucket_make_writeable(bucket TSRMLS_CC); } if (Z_TYPE_PP(pzdata) == IS_UNICODE) { - if (!bucket->is_unicode) { - pefree(bucket->buf.str.val, bucket->is_persistent); - bucket->buf.ustr.len = Z_USTRLEN_PP(pzdata); - bucket->buf.ustr.val = safe_pemalloc(sizeof(UChar), bucket->buf.ustr.len, 0, bucket->is_persistent); - bucket->is_unicode = 1; + if (!bucket->buf_type == IS_UNICODE) { + pefree(bucket->buf.u, bucket->is_persistent); + bucket->buflen = Z_USTRLEN_PP(pzdata); + bucket->buf.u = safe_pemalloc(sizeof(UChar), bucket->buflen, 0, bucket->is_persistent); + bucket->buf_type = IS_UNICODE; } - if (bucket->buf.ustr.len < Z_USTRLEN_PP(pzdata)) { - pefree(bucket->buf.ustr.val, bucket->is_persistent); - bucket->buf.ustr.len = Z_USTRLEN_PP(pzdata); - bucket->buf.ustr.val = safe_pemalloc(sizeof(UChar), bucket->buf.ustr.len, 0, bucket->is_persistent); + if (bucket->buflen < Z_USTRLEN_PP(pzdata)) { + pefree(bucket->buf.u, bucket->is_persistent); + bucket->buflen = Z_USTRLEN_PP(pzdata); + bucket->buf.u = safe_pemalloc(sizeof(UChar), bucket->buflen, 0, bucket->is_persistent); } - bucket->buf.ustr.len = Z_USTRLEN_PP(pzdata); - memcpy(bucket->buf.ustr.val, Z_USTRVAL_PP(pzdata), bucket->buf.ustr.len * sizeof(UChar)); + bucket->buflen = Z_USTRLEN_PP(pzdata); + memcpy(bucket->buf.u, Z_USTRVAL_PP(pzdata), UBYTES(bucket->buflen)); } else { /* string -- or at least string expressable */ SEPARATE_ZVAL_IF_NOT_REF(pzdata); convert_to_string_ex(pzdata); - if (bucket->is_unicode) { - pefree(bucket->buf.ustr.val, bucket->is_persistent); - bucket->buf.str.len = Z_STRLEN_PP(pzdata); - bucket->buf.str.val = pemalloc(bucket->buf.str.len, bucket->is_persistent); - bucket->is_unicode = 0; + if (bucket->buf_type == IS_UNICODE) { + pefree(bucket->buf.u, bucket->is_persistent); + bucket->buflen = Z_STRLEN_PP(pzdata); + bucket->buf.s = pemalloc(bucket->buflen, bucket->is_persistent); + bucket->buf_type = IS_STRING; } - if (bucket->buf.str.len < Z_STRLEN_PP(pzdata)) { - bucket->buf.str.len = Z_STRLEN_PP(pzdata); - bucket->buf.str.val = perealloc(bucket->buf.str.val, bucket->buf.str.len, bucket->is_persistent); + if (bucket->buflen < Z_STRLEN_PP(pzdata)) { + bucket->buflen = Z_STRLEN_PP(pzdata); + bucket->buf.s = perealloc(bucket->buf.s, bucket->buflen, bucket->is_persistent); } - bucket->buf.str.len = Z_STRLEN_PP(pzdata); - memcpy(bucket->buf.str.val, Z_STRVAL_PP(pzdata), bucket->buf.str.len); + bucket->buflen = Z_STRLEN_PP(pzdata); + memcpy(bucket->buf.s, Z_STRVAL_PP(pzdata), bucket->buflen); } } http://cvs.php.net/viewcvs.cgi/php-src/ext/standard/filters.c?r1=1.52&r2=1.53&diff_format=u Index: php-src/ext/standard/filters.c diff -u php-src/ext/standard/filters.c:1.52 php-src/ext/standard/filters.c:1.53 --- php-src/ext/standard/filters.c:1.52 Thu Mar 2 13:12:45 2006 +++ php-src/ext/standard/filters.c Mon Mar 13 04:40:11 2006 @@ -20,7 +20,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: filters.c,v 1.52 2006/03/02 13:12:45 dmitry Exp $ */ +/* $Id: filters.c,v 1.53 2006/03/13 04:40:11 pollita Exp $ */ #include "php.h" #include "php_globals.h" @@ -48,13 +48,13 @@ while (buckets_in->head) { bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC); - if (bucket->is_unicode) { + if (bucket->buf_type == IS_UNICODE) { /* rot13 is silly enough, don't apply it to unicode data */ return PSFS_ERR_FATAL; } - php_strtr(bucket->buf.str.val, bucket->buf.str.len, rot13_from, rot13_to, 52); + php_strtr(bucket->buf.s, bucket->buflen, rot13_from, rot13_to, 52); php_stream_bucket_append(buckets_out, bucket TSRMLS_CC); - consumed += bucket->buf.str.len; + consumed += bucket->buflen; } if (bytes_consumed) { @@ -99,9 +99,9 @@ while (buckets_in->head) { bucket = buckets_in->head; - if (bucket->is_unicode) { + if (bucket->buf_type == IS_UNICODE) { UErrorCode errCode = U_ZERO_ERROR; - int32_t outbuflen = bucket->buf.ustr.len; + int32_t outbuflen = bucket->buflen; int is_persistent = php_stream_is_persistent(stream); UChar *outbuf = peumalloc(outbuflen + 1, is_persistent); @@ -111,13 +111,13 @@ php_stream_bucket_delref(bucket TSRMLS_CC); return PSFS_ERR_FATAL; } - u_strToUpper(outbuf, outbuflen, bucket->buf.ustr.val, bucket->buf.ustr.len, NULL, &errCode); + u_strToUpper(outbuf, outbuflen, bucket->buf.u, bucket->buflen, NULL, &errCode); if (errCode != U_BUFFER_OVERFLOW_ERROR) { break; } outbuflen += 4; outbuf = peurealloc(outbuf, outbuflen + 1, is_persistent); - consumed += UBYTES(bucket->buf.ustr.len); + consumed += UBYTES(bucket->buflen); } if (U_FAILURE(errCode)) { pefree(outbuf, is_persistent); @@ -130,8 +130,8 @@ bucket = php_stream_bucket_new_unicode(stream, outbuf, outbuflen, 1, is_persistent TSRMLS_CC); } else { bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC); - php_strtr(bucket->buf.str.val, bucket->buf.str.len, lowercase, uppercase, 26); - consumed += bucket->buf.str.len; + php_strtr(bucket->buf.s, bucket->buflen, lowercase, uppercase, 26); + consumed += bucket->buflen; } php_stream_bucket_append(buckets_out, bucket TSRMLS_CC); } @@ -157,9 +157,9 @@ while (buckets_in->head) { bucket = buckets_in->head; - if (bucket->is_unicode) { + if (bucket->buf_type == IS_UNICODE) { UErrorCode errCode = U_ZERO_ERROR; - int32_t outbuflen = bucket->buf.ustr.len; + int32_t outbuflen = bucket->buflen; int is_persistent = php_stream_is_persistent(stream); UChar *outbuf = peumalloc(outbuflen + 1, is_persistent); @@ -169,13 +169,13 @@ php_stream_bucket_delref(bucket TSRMLS_CC); return PSFS_ERR_FATAL; } - u_strToLower(outbuf, outbuflen, bucket->buf.ustr.val, bucket->buf.ustr.len, NULL, &errCode); + u_strToLower(outbuf, outbuflen, bucket->buf.u, bucket->buflen, NULL, &errCode); if (errCode != U_BUFFER_OVERFLOW_ERROR) { break; } outbuflen += 4; outbuf = peurealloc(outbuf, outbuflen + 1, is_persistent); - consumed += UBYTES(bucket->buf.ustr.len); + consumed += UBYTES(bucket->buflen); } if (U_FAILURE(errCode)) { pefree(outbuf, is_persistent); @@ -188,8 +188,8 @@ bucket = php_stream_bucket_new_unicode(stream, outbuf, outbuflen, 1, is_persistent TSRMLS_CC); } else { bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC); - php_strtr(bucket->buf.str.val, bucket->buf.str.len, uppercase, lowercase, 26); - consumed += bucket->buf.str.len; + php_strtr(bucket->buf.s, bucket->buflen, uppercase, lowercase, 26); + consumed += bucket->buflen; } php_stream_bucket_append(buckets_out, bucket TSRMLS_CC); } @@ -284,14 +284,14 @@ while (buckets_in->head) { bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC); - if (bucket->is_unicode) { + if (bucket->buf_type == IS_UNICODE) { /* Uh oh! */ return PSFS_ERR_FATAL; } - consumed = bucket->buf.str.len; + consumed = bucket->buflen; - bucket->buf.str.len = php_strip_tags(bucket->buf.str.val, bucket->buf.str.len, &(inst->state), (char *)inst->allowed_tags, inst->allowed_tags_len); + bucket->buflen = php_strip_tags(bucket->buf.s, bucket->buflen, &(inst->state), (char *)inst->allowed_tags, inst->allowed_tags_len); php_stream_bucket_append(buckets_out, bucket TSRMLS_CC); } @@ -1776,7 +1776,7 @@ while (buckets_in->head != NULL) { bucket = buckets_in->head; - if (bucket->is_unicode) { + if (bucket->buf_type == IS_UNICODE) { /* Not a unicode capable filter */ return PSFS_ERR_FATAL; } @@ -1784,7 +1784,7 @@ php_stream_bucket_unlink(bucket TSRMLS_CC); if (strfilter_convert_append_bucket(inst, stream, thisfilter, - buckets_out, bucket->buf.str.val, bucket->buf.str.len, &consumed, + buckets_out, bucket->buf.s, bucket->buflen, &consumed, php_stream_is_persistent(stream) TSRMLS_CC) != SUCCESS) { goto out_failure; } @@ -1903,7 +1903,7 @@ } while ((bucket = buckets_in->head) != NULL) { php_stream_bucket_unlink(bucket TSRMLS_CC); - consumed += bucket->buf.str.len; + consumed += bucket->buflen; php_stream_bucket_append(buckets_out, bucket TSRMLS_CC); } if (bytes_consumed) { http://cvs.php.net/viewcvs.cgi/php-src/ext/standard/streamsfuncs.c?r1=1.67&r2=1.68&diff_format=u Index: php-src/ext/standard/streamsfuncs.c diff -u php-src/ext/standard/streamsfuncs.c:1.67 php-src/ext/standard/streamsfuncs.c:1.68 --- php-src/ext/standard/streamsfuncs.c:1.67 Wed Mar 8 00:43:28 2006 +++ php-src/ext/standard/streamsfuncs.c Mon Mar 13 04:40:11 2006 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: streamsfuncs.c,v 1.67 2006/03/08 00:43:28 pajoye Exp $ */ +/* $Id: streamsfuncs.c,v 1.68 2006/03/13 04:40:11 pollita Exp $ */ #include "php.h" #include "php_globals.h" @@ -489,7 +489,14 @@ add_assoc_zval(return_value, "write_filters", newval); } - add_assoc_long(return_value, "unread_bytes", stream->readbuf_avail); + if (php_stream_reads_unicode(stream)) { + int readbuf_len = u_countChar32(stream->readbuf.u + stream->readpos, stream->writepos - stream->readpos); + add_assoc_long(return_value, "unread_bytes", UBYTES(stream->writepos - stream->readpos)); + add_assoc_long(return_value, "unread_chars", readbuf_len); + } else { + add_assoc_long(return_value, "unread_bytes", stream->writepos - stream->readpos); + add_assoc_long(return_value, "unread_chars", stream->writepos - stream->readpos); + } add_assoc_bool(return_value, "seekable", (stream->ops->seek) && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0); if (stream->orig_path) { @@ -666,7 +673,7 @@ if (stream == NULL) { continue; } - if ((stream->readbuf_avail) > 0) { + if ((stream->writepos - stream->readpos) > 0) { /* allow readable non-descriptor based streams to participate in stream_select. * Non-descriptor streams will only "work" if they have previously buffered the * data. Not ideal, but better than nothing. http://cvs.php.net/viewcvs.cgi/php-src/ext/zlib/zlib_filter.c?r1=1.9&r2=1.10&diff_format=u Index: php-src/ext/zlib/zlib_filter.c diff -u php-src/ext/zlib/zlib_filter.c:1.9 php-src/ext/zlib/zlib_filter.c:1.10 --- php-src/ext/zlib/zlib_filter.c:1.9 Sun Jan 1 13:09:56 2006 +++ php-src/ext/zlib/zlib_filter.c Mon Mar 13 04:40:11 2006 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zlib_filter.c,v 1.9 2006/01/01 13:09:56 sniper Exp $ */ +/* $Id: zlib_filter.c,v 1.10 2006/03/13 04:40:11 pollita Exp $ */ #include "php.h" #include "php_zlib.h" @@ -81,18 +81,18 @@ bucket = buckets_in->head; - if (bucket->is_unicode) { + if (bucket->buf_type == IS_UNICODE) { /* inflation not allowed for unicode data */ return PSFS_ERR_FATAL; } bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC); - while (bin < bucket->buf.str.len) { - desired = bucket->buf.str.len - bin; + while (bin < bucket->buflen) { + desired = bucket->buflen - bin; if (desired > data->inbuf_len) { desired = data->inbuf_len; } - memcpy(data->strm.next_in, bucket->buf.str.val + bin, desired); + memcpy(data->strm.next_in, bucket->buf.s + bin, desired); data->strm.avail_in = desired; status = inflate(&(data->strm), flags & PSFS_FLAG_FLUSH_CLOSE ? Z_FINISH : Z_SYNC_FLUSH); @@ -116,7 +116,7 @@ exit_status = PSFS_PASS_ON; } } - consumed += bucket->buf.str.len; + consumed += bucket->buflen; php_stream_bucket_delref(bucket TSRMLS_CC); } @@ -196,19 +196,19 @@ bucket = buckets_in->head; - if (bucket->is_unicode) { + if (bucket->buf_type == IS_UNICODE) { /* inflation not allowed for unicode data */ return PSFS_ERR_FATAL; } bucket = php_stream_bucket_make_writeable(bucket TSRMLS_CC); - while (bin < bucket->buf.str.len) { - desired = bucket->buf.str.len - bin; + while (bin < bucket->buflen) { + desired = bucket->buflen - bin; if (desired > data->inbuf_len) { desired = data->inbuf_len; } - memcpy(data->strm.next_in, bucket->buf.str.val + bin, desired); + memcpy(data->strm.next_in, bucket->buf.s + bin, desired); data->strm.avail_in = desired; status = deflate(&(data->strm), flags & PSFS_FLAG_FLUSH_CLOSE ? Z_FULL_FLUSH : (flags & PSFS_FLAG_FLUSH_INC ? Z_SYNC_FLUSH : Z_NO_FLUSH)); @@ -233,7 +233,7 @@ exit_status = PSFS_PASS_ON; } } - consumed += bucket->buf.str.len; + consumed += bucket->buflen; php_stream_bucket_delref(bucket TSRMLS_CC); } http://cvs.php.net/viewcvs.cgi/php-src/ext/bz2/bz2_filter.c?r1=1.6&r2=1.7&diff_format=u Index: php-src/ext/bz2/bz2_filter.c diff -u php-src/ext/bz2/bz2_filter.c:1.6 php-src/ext/bz2/bz2_filter.c:1.7 --- php-src/ext/bz2/bz2_filter.c:1.6 Sun Jan 1 13:09:48 2006 +++ php-src/ext/bz2/bz2_filter.c Mon Mar 13 04:40:11 2006 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: bz2_filter.c,v 1.6 2006/01/01 13:09:48 sniper Exp $ */ +/* $Id: bz2_filter.c,v 1.7 2006/03/13 04:40:11 pollita Exp $ */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -82,18 +82,18 @@ bucket = buckets_in->head; - if (bucket->is_unicode) { + if (bucket->buf_type == IS_UNICODE) { /* decompression not allowed for unicode data */ return PSFS_ERR_FATAL; } bucket = php_stream_bucket_make_writeable(bucket TSRMLS_CC); - while (bin < bucket->buf.str.len) { - desired = bucket->buf.str.len - bin; + while (bin < bucket->buflen) { + desired = bucket->buflen - bin; if (desired > data->inbuf_len) { desired = data->inbuf_len; } - memcpy(data->strm.next_in, bucket->buf.str.val + bin, desired); + memcpy(data->strm.next_in, bucket->buf.s + bin, desired); data->strm.avail_in = desired; status = BZ2_bzDecompress(&(data->strm)); @@ -195,19 +195,19 @@ bucket = buckets_in->head; - if (bucket->is_unicode) { + if (bucket->buf_type == IS_UNICODE) { /* compression not allowed for unicode data */ return PSFS_ERR_FATAL; } bucket = php_stream_bucket_make_writeable(bucket TSRMLS_CC); - while (bin < bucket->buf.str.len) { - desired = bucket->buf.str.len - bin; + while (bin < bucket->buflen) { + desired = bucket->buflen - bin; if (desired > data->inbuf_len) { desired = data->inbuf_len; } - memcpy(data->strm.next_in, bucket->buf.str.val + bin, desired); + memcpy(data->strm.next_in, bucket->buf.s + bin, desired); data->strm.avail_in = desired; status = BZ2_bzCompress(&(data->strm), flags & PSFS_FLAG_FLUSH_CLOSE ? BZ_FINISH : (flags & PSFS_FLAG_FLUSH_INC ? BZ_FLUSH : BZ_RUN)); http://cvs.php.net/viewcvs.cgi/php-src/ext/unicode/unicode_filter.c?r1=1.4&r2=1.5&diff_format=u Index: php-src/ext/unicode/unicode_filter.c diff -u php-src/ext/unicode/unicode_filter.c:1.4 php-src/ext/unicode/unicode_filter.c:1.5 --- php-src/ext/unicode/unicode_filter.c:1.4 Sun Jan 1 13:09:56 2006 +++ php-src/ext/unicode/unicode_filter.c Mon Mar 13 04:40:11 2006 @@ -14,7 +14,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: unicode_filter.c,v 1.4 2006/01/01 13:09:56 sniper Exp $ */ +/* $Id: unicode_filter.c,v 1.5 2006/03/13 04:40:11 pollita Exp $ */ #include "php.h" @@ -53,19 +53,19 @@ data = (php_unicode_filter_data *)(thisfilter->abstract); while (buckets_in->head) { php_stream_bucket *bucket = buckets_in->head; - UChar *src = bucket->buf.ustr.val; + UChar *src = bucket->buf.u; php_stream_bucket_unlink(bucket TSRMLS_CC); - if (!bucket->is_unicode) { + if (!bucket->buf_type == IS_UNICODE) { /* Already ASCII, can't really do anything with it */ - consumed += bucket->buf.str.len; + consumed += bucket->buflen; php_stream_bucket_append(buckets_out, bucket TSRMLS_CC); exit_status = PSFS_PASS_ON; continue; } - while (src < (bucket->buf.ustr.val + bucket->buf.ustr.len)) { - int remaining = bucket->buf.ustr.len - (src - bucket->buf.ustr.val); + while (src < (bucket->buf.u + bucket->buflen)) { + int remaining = bucket->buflen - (src - bucket->buf.u); char *destp, *destbuf; int32_t destlen = UCNV_GET_MAX_BYTES_FOR_STRING(remaining, ucnv_getMaxCharSize(data->conv)); UErrorCode errCode = U_ZERO_ERROR; @@ -78,7 +78,7 @@ php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC); exit_status = PSFS_PASS_ON; } - consumed += UBYTES(bucket->buf.ustr.len); + consumed += UBYTES(bucket->buflen); php_stream_bucket_delref(bucket TSRMLS_CC); } @@ -124,19 +124,19 @@ data = (php_unicode_filter_data *)(thisfilter->abstract); while (buckets_in->head) { php_stream_bucket *bucket = buckets_in->head; - char *src = bucket->buf.str.val; + char *src = bucket->buf.s; php_stream_bucket_unlink(bucket TSRMLS_CC); - if (bucket->is_unicode) { + if (bucket->buf_type == IS_UNICODE) { /* already in unicode, nothing to do */ - consumed += UBYTES(bucket->buf.ustr.len); + consumed += UBYTES(bucket->buflen); php_stream_bucket_append(buckets_out, bucket TSRMLS_CC); exit_status = PSFS_PASS_ON; continue; } - while (src < (bucket->buf.str.val + bucket->buf.str.len)) { - int remaining = bucket->buf.str.len - (src - bucket->buf.str.val); + while (src < (bucket->buf.s + bucket->buflen)) { + int remaining = bucket->buflen - (src - bucket->buf.s); UChar *destp, *destbuf; int32_t destlen = UCNV_GET_MAX_BYTES_FOR_STRING(remaining, ucnv_getMaxCharSize(data->conv)); UErrorCode errCode = U_ZERO_ERROR; @@ -150,7 +150,7 @@ php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC); exit_status = PSFS_PASS_ON; } - consumed += bucket->buf.str.len; + consumed += bucket->buflen; php_stream_bucket_delref(bucket TSRMLS_CC); }
« previous php.cvs (#37242) next »