--- php5.2-200809191430\ext\bz2\bz2_filter.c 2008-01-13 00:35:00.000000000 +0100 +++ php5.2-200809181030\ext\bz2\bz2_filter.c 2008-09-19 18:41:52.000000000 +0200 @@ -27,6 +27,13 @@ /* {{{ data structure */ +enum strm_status { + Uninitialised, + Running, + Finished +}; + + typedef struct _php_bz2_filter_data { int persistent; bz_stream strm; @@ -34,6 +41,11 @@ size_t inbuf_len; char *outbuf; size_t outbuf_len; + + /* Decompress options */ + enum strm_status status; + unsigned int small_footprint : 1; + int expect_concatenated : 1; } php_bz2_filter_data; /* }}} */ @@ -65,7 +77,7 @@ php_bz2_filter_data *data; php_stream_bucket *bucket; size_t consumed = 0; - int status; + int bzlib_status; php_stream_filter_status_t exit_status = PSFS_FEED_ME; bz_stream *streamp; @@ -82,47 +94,72 @@ bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC); while (bin < bucket->buflen) { - desired = bucket->buflen - bin; - if (desired > data->inbuf_len) { - desired = data->inbuf_len; - } - memcpy(data->strm.next_in, bucket->buf + bin, desired); - data->strm.avail_in = desired; + if (data->status == Uninitialised) { + bzlib_status = BZ2_bzDecompressInit(streamp, 0, data->small_footprint); - status = BZ2_bzDecompress(&(data->strm)); - if (status != BZ_OK && status != BZ_STREAM_END) { - /* Something bad happened */ - php_stream_bucket_delref(bucket TSRMLS_CC); - return PSFS_ERR_FATAL; - } - desired -= data->strm.avail_in; /* desired becomes what we consumed this round through */ - data->strm.next_in = data->inbuf; - data->strm.avail_in = 0; - consumed += desired; - bin += desired; + if (BZ_OK != bzlib_status) + return PSFS_ERR_FATAL; - if (data->strm.avail_out < data->outbuf_len) { - php_stream_bucket *out_bucket; - size_t bucketlen = data->outbuf_len - data->strm.avail_out; - out_bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0 TSRMLS_CC); - php_stream_bucket_append(buckets_out, out_bucket TSRMLS_CC); - data->strm.avail_out = data->outbuf_len; - data->strm.next_out = data->outbuf; - exit_status = PSFS_PASS_ON; - } else if (status == BZ_STREAM_END && data->strm.avail_out >= data->outbuf_len) { - /* no more data to decompress, and nothing was spat out */ - php_stream_bucket_delref(bucket TSRMLS_CC); - return PSFS_PASS_ON; - } + data->status = Running; + } + + if (data->status == Running) { + desired = bucket->buflen - bin; + if (desired > data->inbuf_len) { + desired = data->inbuf_len; + } + memcpy(data->strm.next_in, bucket->buf + bin, desired); + data->strm.avail_in = desired; + + bzlib_status = BZ2_bzDecompress(&(data->strm)); + + if (bzlib_status == BZ_STREAM_END) { + BZ2_bzDecompressEnd(&(data->strm)); + if (data->expect_concatenated) + data->status = Uninitialised; + else + data->status = Finished; + } else + if (bzlib_status != BZ_OK) { + /* Something bad happened */ + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bzip decompress error %d.", bzlib_status); + + php_stream_bucket_delref(bucket TSRMLS_CC); + return PSFS_ERR_FATAL; + } + desired -= data->strm.avail_in; /* desired becomes what we consumed this round through */ + data->strm.next_in = data->inbuf; + data->strm.avail_in = 0; + consumed += desired; + bin += desired; + + if (data->strm.avail_out < data->outbuf_len) { + php_stream_bucket *out_bucket; + size_t bucketlen = data->outbuf_len - data->strm.avail_out; + out_bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0 TSRMLS_CC); + php_stream_bucket_append(buckets_out, out_bucket TSRMLS_CC); + data->strm.avail_out = data->outbuf_len; + data->strm.next_out = data->outbuf; + exit_status = PSFS_PASS_ON; + } else if (bzlib_status == BZ_STREAM_END && data->strm.avail_out >= data->outbuf_len) { + /* no more data to decompress, and nothing was spat out */ + php_stream_bucket_delref(bucket TSRMLS_CC); + return PSFS_PASS_ON; + } + } else { + consumed += bucket->buflen; + break; + } } + php_stream_bucket_delref(bucket TSRMLS_CC); } - if (flags & PSFS_FLAG_FLUSH_CLOSE) { + if ((data->status == Running) && (flags & PSFS_FLAG_FLUSH_CLOSE)) { /* Spit it out! */ - status = BZ_OK; - while (status == BZ_OK) { - status = BZ2_bzDecompress(&(data->strm)); + bzlib_status = BZ_OK; + while (bzlib_status == BZ_OK) { + bzlib_status = BZ2_bzDecompress(&(data->strm)); if (data->strm.avail_out < data->outbuf_len) { size_t bucketlen = data->outbuf_len - data->strm.avail_out; @@ -131,7 +168,7 @@ data->strm.avail_out = data->outbuf_len; data->strm.next_out = data->outbuf; exit_status = PSFS_PASS_ON; - } else if (status == BZ_OK) { + } else if (bzlib_status == BZ_OK) { break; } } @@ -148,7 +185,7 @@ { if (thisfilter && thisfilter->abstract) { php_bz2_filter_data *data = thisfilter->abstract; - BZ2_bzDecompressEnd(&(data->strm)); + if (data->status == Running) BZ2_bzDecompressEnd(&(data->strm)); pefree(data->inbuf, data->persistent); pefree(data->outbuf, data->persistent); pefree(data, data->persistent); @@ -275,7 +312,7 @@ { php_stream_filter_ops *fops = NULL; php_bz2_filter_data *data; - int status; + int status = BZ_OK; /* Create this filter */ data = pecalloc(1, sizeof(php_bz2_filter_data), persistent); @@ -307,12 +344,22 @@ } if (strcasecmp(filtername, "bzip2.decompress") == 0) { - int smallFootprint = 0; - + data->small_footprint = 0; + data->expect_concatenated = 0; + if (filterparams) { zval **tmpzval = NULL; if (Z_TYPE_P(filterparams) == IS_ARRAY || Z_TYPE_P(filterparams) == IS_OBJECT) { + + if (SUCCESS == zend_hash_find(HASH_OF(filterparams), "concatenated", sizeof("concatenated"), (void **) &tmpzval) ) { + SEPARATE_ZVAL(tmpzval); + convert_to_boolean_ex(tmpzval); + data->expect_concatenated = Z_LVAL_PP(tmpzval); + zval_ptr_dtor(tmpzval); + tmpzval = NULL; + } + zend_hash_find(HASH_OF(filterparams), "small", sizeof("small"), (void **) &tmpzval); } else { tmpzval = &filterparams; @@ -321,12 +368,12 @@ if (tmpzval) { SEPARATE_ZVAL(tmpzval); convert_to_boolean_ex(tmpzval); - smallFootprint = Z_LVAL_PP(tmpzval); + data->small_footprint = Z_LVAL_PP(tmpzval); zval_ptr_dtor(tmpzval); } } - status = BZ2_bzDecompressInit(&(data->strm), 0, smallFootprint); + data->status = Uninitialised; fops = &php_bz2_decompress_ops; } else if (strcasecmp(filtername, "bzip2.compress") == 0) { int blockSize100k = PHP_BZ2_FILTER_DEFAULT_BLOCKSIZE;