1. --- php5.2-200809191430\ext\bz2\bz2_filter.c    2008-01-13 00:35:00.000000000 +0100
  2. +++ php5.2-200809181030\ext\bz2\bz2_filter.c    2008-09-19 18:41:52.000000000 +0200
  3. @@ -27,6 +27,13 @@
  4.  
  5.  /* {{{ data structure */
  6.  
  7. +enum strm_status {
  8. +    Uninitialised,
  9. +    Running,
  10. +    Finished
  11. +};
  12. +    
  13. +
  14.  typedef struct _php_bz2_filter_data {
  15.     int persistent;
  16.     bz_stream strm;
  17. @@ -34,6 +41,11 @@
  18.     size_t inbuf_len;
  19.     char *outbuf;
  20.     size_t outbuf_len;
  21. +  
  22. +   /* Decompress options */
  23. +   enum strm_status status;
  24. +   unsigned int small_footprint : 1;
  25. +    int expect_concatenated : 1;          
  26.  } php_bz2_filter_data;
  27.  
  28.  /* }}} */
  29. @@ -65,7 +77,7 @@
  30.     php_bz2_filter_data *data;
  31.     php_stream_bucket *bucket;
  32.     size_t consumed = 0;
  33. -   int status;
  34. +   int bzlib_status;
  35.     php_stream_filter_status_t exit_status = PSFS_FEED_ME;
  36.     bz_stream *streamp;
  37.  
  38. @@ -82,6 +94,16 @@
  39.  
  40.         bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC);
  41.         while (bin < bucket->buflen) {
  42. +            if (data->status == Uninitialised) {                
  43. +                bzlib_status = BZ2_bzDecompressInit(streamp, 0, data->small_footprint);
  44. +
  45. +                if (BZ_OK != bzlib_status)
  46. +                    return PSFS_ERR_FATAL;
  47. +
  48. +                data->status = Running;
  49. +            }
  50. +                    
  51. +            if (data->status == Running) {
  52.             desired = bucket->buflen - bin;
  53.             if (desired > data->inbuf_len) {
  54.                 desired = data->inbuf_len;
  55. @@ -89,9 +111,19 @@
  56.             memcpy(data->strm.next_in, bucket->buf + bin, desired);
  57.             data->strm.avail_in = desired;
  58.  
  59. -           status = BZ2_bzDecompress(&(data->strm));
  60. -           if (status != BZ_OK && status != BZ_STREAM_END) {
  61. +               bzlib_status = BZ2_bzDecompress(&(data->strm));
  62. +              
  63. +               if (bzlib_status == BZ_STREAM_END) {
  64. +                    BZ2_bzDecompressEnd(&(data->strm));
  65. +                    if (data->expect_concatenated)
  66. +                        data->status = Uninitialised;
  67. +                    else
  68. +                        data->status = Finished;
  69. +                } else
  70. +               if (bzlib_status != BZ_OK) {
  71.                 /* Something bad happened */
  72. +                   php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bzip decompress error %d.", bzlib_status);
  73. +    
  74.                 php_stream_bucket_delref(bucket TSRMLS_CC);
  75.                 return PSFS_ERR_FATAL;
  76.             }
  77. @@ -109,20 +141,25 @@
  78.                 data->strm.avail_out = data->outbuf_len;
  79.                 data->strm.next_out = data->outbuf;
  80.                 exit_status = PSFS_PASS_ON;
  81. -           } else if (status == BZ_STREAM_END && data->strm.avail_out >= data->outbuf_len) {
  82. +               } else if (bzlib_status == BZ_STREAM_END && data->strm.avail_out >= data->outbuf_len) {
  83.                 /* no more data to decompress, and nothing was spat out */
  84.                 php_stream_bucket_delref(bucket TSRMLS_CC);
  85.                 return PSFS_PASS_ON;
  86.             }
  87. +           } else {
  88. +                consumed += bucket->buflen;
  89. +                break;
  90.         }
  91. +       }
  92. +
  93.         php_stream_bucket_delref(bucket TSRMLS_CC);
  94.     }
  95.  
  96. -   if (flags & PSFS_FLAG_FLUSH_CLOSE) {
  97. +   if ((data->status == Running) && (flags & PSFS_FLAG_FLUSH_CLOSE)) {
  98.         /* Spit it out! */
  99. -       status = BZ_OK;
  100. -       while (status == BZ_OK) {
  101. -           status = BZ2_bzDecompress(&(data->strm));
  102. +       bzlib_status = BZ_OK;
  103. +       while (bzlib_status == BZ_OK) {
  104. +           bzlib_status = BZ2_bzDecompress(&(data->strm));
  105.             if (data->strm.avail_out < data->outbuf_len) {
  106.                 size_t bucketlen = data->outbuf_len - data->strm.avail_out;
  107.  
  108. @@ -131,7 +168,7 @@
  109.                 data->strm.avail_out = data->outbuf_len;
  110.                 data->strm.next_out = data->outbuf;
  111.                 exit_status = PSFS_PASS_ON;
  112. -           } else if (status == BZ_OK) {
  113. +           } else if (bzlib_status == BZ_OK) {
  114.                 break;
  115.             }
  116.         }
  117. @@ -148,7 +185,7 @@
  118.  {
  119.     if (thisfilter && thisfilter->abstract) {
  120.         php_bz2_filter_data *data = thisfilter->abstract;
  121. -       BZ2_bzDecompressEnd(&(data->strm));
  122. +       if (data->status == Running) BZ2_bzDecompressEnd(&(data->strm));
  123.         pefree(data->inbuf, data->persistent);
  124.         pefree(data->outbuf, data->persistent);
  125.         pefree(data, data->persistent);
  126. @@ -275,7 +312,7 @@
  127.  {
  128.     php_stream_filter_ops *fops = NULL;
  129.     php_bz2_filter_data *data;
  130. -   int status;
  131. +   int status = BZ_OK;
  132.  
  133.     /* Create this filter */
  134.     data = pecalloc(1, sizeof(php_bz2_filter_data), persistent);
  135. @@ -307,12 +344,22 @@
  136.     }
  137.  
  138.     if (strcasecmp(filtername, "bzip2.decompress") == 0) {
  139. -       int smallFootprint = 0;
  140. +       data->small_footprint = 0;
  141. +       data->expect_concatenated = 0;
  142.  
  143.         if (filterparams) {
  144.             zval **tmpzval = NULL;
  145.  
  146.             if (Z_TYPE_P(filterparams) == IS_ARRAY || Z_TYPE_P(filterparams) == IS_OBJECT) {
  147. +                
  148. +                if (SUCCESS == zend_hash_find(HASH_OF(filterparams), "concatenated", sizeof("concatenated"), (void **) &tmpzval) ) {
  149. +                   SEPARATE_ZVAL(tmpzval);
  150. +                   convert_to_boolean_ex(tmpzval);
  151. +                   data->expect_concatenated = Z_LVAL_PP(tmpzval);
  152. +                   zval_ptr_dtor(tmpzval);
  153. +                   tmpzval = NULL;
  154. +                }
  155. +                
  156.                 zend_hash_find(HASH_OF(filterparams), "small", sizeof("small"), (void **) &tmpzval);
  157.             } else {
  158.                 tmpzval = &filterparams;
  159. @@ -321,12 +368,12 @@
  160.             if (tmpzval) {
  161.                 SEPARATE_ZVAL(tmpzval);
  162.                 convert_to_boolean_ex(tmpzval);
  163. -               smallFootprint = Z_LVAL_PP(tmpzval);
  164. +               data->small_footprint = Z_LVAL_PP(tmpzval);
  165.                 zval_ptr_dtor(tmpzval);
  166.             }
  167.         }
  168.  
  169. -       status = BZ2_bzDecompressInit(&(data->strm), 0, smallFootprint);
  170. +       data->status = Uninitialised;
  171.         fops = &php_bz2_decompress_ops;
  172.     } else if (strcasecmp(filtername, "bzip2.compress") == 0) {
  173.         int blockSize100k = PHP_BZ2_FILTER_DEFAULT_BLOCKSIZE;
  174.