Back to index

php5  5.3.10
bz2_filter.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Authors: Sara Golemon (pollita@php.net)                              |
00016    +----------------------------------------------------------------------+
00017 */
00018 
00019 /* $Id: bz2_filter.c 321634 2012-01-01 13:15:04Z felipe $ */
00020 
00021 #ifdef HAVE_CONFIG_H
00022 #include "config.h"
00023 #endif
00024 
00025 #include "php.h"
00026 #include "php_bz2.h"
00027 
00028 /* {{{ data structure */
00029 
00030 enum strm_status {
00031     PHP_BZ2_UNITIALIZED,
00032     PHP_BZ2_RUNNING,
00033     PHP_BZ2_FINISHED
00034 };
00035 
00036 typedef struct _php_bz2_filter_data {
00037        int persistent;
00038        bz_stream strm;
00039        char *inbuf;
00040        size_t inbuf_len;
00041        char *outbuf;
00042        size_t outbuf_len;
00043        
00044        /* Decompress options */
00045        enum strm_status status;
00046        unsigned int small_footprint : 1;
00047        unsigned int expect_concatenated : 1;
00048 } php_bz2_filter_data;
00049 
00050 /* }}} */
00051 
00052 /* {{{ Memory management wrappers */
00053 
00054 static void *php_bz2_alloc(void *opaque, int items, int size)
00055 {
00056        return (void *)safe_pemalloc(items, size, 0, ((php_bz2_filter_data*)opaque)->persistent);
00057 }
00058 
00059 static void php_bz2_free(void *opaque, void *address)
00060 {
00061        pefree((void *)address, ((php_bz2_filter_data*)opaque)->persistent);
00062 }
00063 /* }}} */
00064 
00065 /* {{{ bzip2.decompress filter implementation */
00066 
00067 static php_stream_filter_status_t php_bz2_decompress_filter(
00068        php_stream *stream,
00069        php_stream_filter *thisfilter,
00070        php_stream_bucket_brigade *buckets_in,
00071        php_stream_bucket_brigade *buckets_out,
00072        size_t *bytes_consumed,
00073        int flags
00074        TSRMLS_DC)
00075 {
00076        php_bz2_filter_data *data;
00077        php_stream_bucket *bucket;
00078        size_t consumed = 0;
00079        int status;
00080        php_stream_filter_status_t exit_status = PSFS_FEED_ME;
00081        bz_stream *streamp;
00082 
00083        if (!thisfilter || !thisfilter->abstract) {
00084               /* Should never happen */
00085               return PSFS_ERR_FATAL;
00086        }
00087 
00088        data = (php_bz2_filter_data *)(thisfilter->abstract);
00089        streamp = &(data->strm);
00090 
00091        while (buckets_in->head) {
00092               size_t bin = 0, desired;
00093 
00094               bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC);
00095               while (bin < bucket->buflen) {
00096                      if (data->status == PHP_BZ2_UNITIALIZED) {
00097                             status = BZ2_bzDecompressInit(streamp, 0, data->small_footprint);
00098 
00099                             if (BZ_OK != status) {
00100                                    return PSFS_ERR_FATAL;
00101                             }
00102 
00103                             data->status = PHP_BZ2_RUNNING;
00104                      }
00105 
00106                      if (data->status != PHP_BZ2_RUNNING) {
00107                             consumed += bucket->buflen;
00108                             break;
00109                      }
00110 
00111                      desired = bucket->buflen - bin;
00112                      if (desired > data->inbuf_len) {
00113                             desired = data->inbuf_len;
00114                      }
00115                      memcpy(data->strm.next_in, bucket->buf + bin, desired);
00116                      data->strm.avail_in = desired;
00117 
00118                      status = BZ2_bzDecompress(&(data->strm));
00119 
00120                      if (status == BZ_STREAM_END) {
00121                             BZ2_bzDecompressEnd(&(data->strm));
00122                             if (data->expect_concatenated) {
00123                                    data->status = PHP_BZ2_UNITIALIZED;
00124                             } else {
00125                                    data->status = PHP_BZ2_FINISHED;
00126                             }
00127                      } else if (status != BZ_OK) {
00128                             /* Something bad happened */
00129                             php_stream_bucket_delref(bucket TSRMLS_CC);
00130                             return PSFS_ERR_FATAL;
00131                      }
00132                      desired -= data->strm.avail_in; /* desired becomes what we consumed this round through */
00133                      data->strm.next_in = data->inbuf;
00134                      data->strm.avail_in = 0;
00135                      consumed += desired;
00136                      bin += desired;
00137 
00138                      if (data->strm.avail_out < data->outbuf_len) {
00139                             php_stream_bucket *out_bucket;
00140                             size_t bucketlen = data->outbuf_len - data->strm.avail_out;
00141                             out_bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0 TSRMLS_CC);
00142                             php_stream_bucket_append(buckets_out, out_bucket TSRMLS_CC);
00143                             data->strm.avail_out = data->outbuf_len;
00144                             data->strm.next_out = data->outbuf;
00145                             exit_status = PSFS_PASS_ON;
00146                      } else if (status == BZ_STREAM_END && data->strm.avail_out >= data->outbuf_len) {
00147                             /* no more data to decompress, and nothing was spat out */
00148                             php_stream_bucket_delref(bucket TSRMLS_CC);
00149                             return PSFS_PASS_ON;
00150                      }
00151               }
00152 
00153               php_stream_bucket_delref(bucket TSRMLS_CC);
00154        }
00155 
00156        if ((data->status == PHP_BZ2_RUNNING) && (flags & PSFS_FLAG_FLUSH_CLOSE)) {
00157               /* Spit it out! */
00158               status = BZ_OK;
00159               while (status == BZ_OK) {
00160                      status = BZ2_bzDecompress(&(data->strm));
00161                      if (data->strm.avail_out < data->outbuf_len) {
00162                             size_t bucketlen = data->outbuf_len - data->strm.avail_out;
00163 
00164                             bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0 TSRMLS_CC);
00165                             php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
00166                             data->strm.avail_out = data->outbuf_len;
00167                             data->strm.next_out = data->outbuf;
00168                             exit_status = PSFS_PASS_ON;
00169                      } else if (status == BZ_OK) {
00170                             break;
00171                      }
00172               }
00173        }
00174 
00175        if (bytes_consumed) {
00176               *bytes_consumed = consumed;
00177        }
00178 
00179        return exit_status;
00180 }
00181 
00182 static void php_bz2_decompress_dtor(php_stream_filter *thisfilter TSRMLS_DC)
00183 {
00184        if (thisfilter && thisfilter->abstract) {
00185               php_bz2_filter_data *data = thisfilter->abstract;
00186               if (data->status == PHP_BZ2_RUNNING) {
00187                      BZ2_bzDecompressEnd(&(data->strm));
00188               }
00189               pefree(data->inbuf, data->persistent);
00190               pefree(data->outbuf, data->persistent);
00191               pefree(data, data->persistent);
00192        }
00193 }
00194 
00195 static php_stream_filter_ops php_bz2_decompress_ops = {
00196        php_bz2_decompress_filter,
00197        php_bz2_decompress_dtor,
00198        "bzip2.decompress"
00199 };
00200 /* }}} */
00201 
00202 /* {{{ bzip2.compress filter implementation */
00203 
00204 static php_stream_filter_status_t php_bz2_compress_filter(
00205        php_stream *stream,
00206        php_stream_filter *thisfilter,
00207        php_stream_bucket_brigade *buckets_in,
00208        php_stream_bucket_brigade *buckets_out,
00209        size_t *bytes_consumed,
00210        int flags
00211        TSRMLS_DC)
00212 {
00213        php_bz2_filter_data *data;
00214        php_stream_bucket *bucket;
00215        size_t consumed = 0;
00216        int status;
00217        php_stream_filter_status_t exit_status = PSFS_FEED_ME;
00218        bz_stream *streamp;
00219 
00220        if (!thisfilter || !thisfilter->abstract) {
00221               /* Should never happen */
00222               return PSFS_ERR_FATAL;
00223        }
00224 
00225        data = (php_bz2_filter_data *)(thisfilter->abstract);
00226        streamp = &(data->strm);
00227 
00228        while (buckets_in->head) {
00229               size_t bin = 0, desired;
00230 
00231               bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC);
00232 
00233               while (bin < bucket->buflen) {
00234                      desired = bucket->buflen - bin;
00235                      if (desired > data->inbuf_len) {
00236                             desired = data->inbuf_len;
00237                      }
00238                      memcpy(data->strm.next_in, bucket->buf + bin, desired);
00239                      data->strm.avail_in = desired;
00240 
00241                      status = BZ2_bzCompress(&(data->strm), flags & PSFS_FLAG_FLUSH_CLOSE ? BZ_FINISH : (flags & PSFS_FLAG_FLUSH_INC ? BZ_FLUSH : BZ_RUN));
00242                      if (status != BZ_RUN_OK && status != BZ_FLUSH_OK && status != BZ_FINISH_OK) {
00243                             /* Something bad happened */
00244                             php_stream_bucket_delref(bucket TSRMLS_CC);
00245                             return PSFS_ERR_FATAL;
00246                      }
00247                      desired -= data->strm.avail_in; /* desired becomes what we consumed this round through */
00248                      data->strm.next_in = data->inbuf;
00249                      data->strm.avail_in = 0;
00250                      consumed += desired;
00251                      bin += desired;
00252 
00253                      if (data->strm.avail_out < data->outbuf_len) {
00254                             php_stream_bucket *out_bucket;
00255                             size_t bucketlen = data->outbuf_len - data->strm.avail_out;
00256 
00257                             out_bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0 TSRMLS_CC);
00258                             php_stream_bucket_append(buckets_out, out_bucket TSRMLS_CC);
00259                             data->strm.avail_out = data->outbuf_len;
00260                             data->strm.next_out = data->outbuf;
00261                             exit_status = PSFS_PASS_ON;
00262                      }
00263               }
00264               php_stream_bucket_delref(bucket TSRMLS_CC);
00265        }
00266 
00267        if (flags & PSFS_FLAG_FLUSH_CLOSE) {
00268               /* Spit it out! */
00269               status = BZ_FINISH_OK;
00270               while (status == BZ_FINISH_OK) {
00271                      status = BZ2_bzCompress(&(data->strm), BZ_FINISH);
00272                      if (data->strm.avail_out < data->outbuf_len) {
00273                             size_t bucketlen = data->outbuf_len - data->strm.avail_out;
00274 
00275                             bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0 TSRMLS_CC);
00276                             php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
00277                             data->strm.avail_out = data->outbuf_len;
00278                             data->strm.next_out = data->outbuf;
00279                             exit_status = PSFS_PASS_ON;
00280                      }
00281               }
00282        }
00283 
00284        if (bytes_consumed) {
00285               *bytes_consumed = consumed;
00286        }
00287        return exit_status;
00288 }
00289 
00290 static void php_bz2_compress_dtor(php_stream_filter *thisfilter TSRMLS_DC)
00291 {
00292        if (thisfilter && thisfilter->abstract) {
00293               php_bz2_filter_data *data = thisfilter->abstract;
00294               BZ2_bzCompressEnd(&(data->strm));
00295               pefree(data->inbuf, data->persistent);
00296               pefree(data->outbuf, data->persistent);
00297               pefree(data, data->persistent);
00298        }
00299 }
00300 
00301 static php_stream_filter_ops php_bz2_compress_ops = {
00302        php_bz2_compress_filter,
00303        php_bz2_compress_dtor,
00304        "bzip2.compress"
00305 };
00306 
00307 /* }}} */
00308 
00309 /* {{{ bzip2.* common factory */
00310 
00311 static php_stream_filter *php_bz2_filter_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
00312 {
00313        php_stream_filter_ops *fops = NULL;
00314        php_bz2_filter_data *data;
00315        int status = BZ_OK;
00316 
00317        /* Create this filter */
00318        data = pecalloc(1, sizeof(php_bz2_filter_data), persistent);
00319        if (!data) {
00320               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %zu bytes", sizeof(php_bz2_filter_data));
00321               return NULL;
00322        }
00323 
00324        /* Circular reference */
00325        data->strm.opaque = (void *) data;
00326 
00327        data->strm.bzalloc = php_bz2_alloc;
00328        data->strm.bzfree = php_bz2_free;
00329        data->persistent = persistent;
00330        data->strm.avail_out = data->outbuf_len = data->inbuf_len = 2048;
00331        data->strm.next_in = data->inbuf = (char *) pemalloc(data->inbuf_len, persistent);
00332        if (!data->inbuf) {
00333               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %zu bytes", data->inbuf_len);
00334               pefree(data, persistent);
00335               return NULL;
00336        }
00337        data->strm.avail_in = 0;
00338        data->strm.next_out = data->outbuf = (char *) pemalloc(data->outbuf_len, persistent);
00339        if (!data->outbuf) {
00340               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %zu bytes", data->outbuf_len);
00341               pefree(data->inbuf, persistent);
00342               pefree(data, persistent);
00343               return NULL;
00344        }
00345 
00346        if (strcasecmp(filtername, "bzip2.decompress") == 0) {
00347               data->small_footprint = 0;
00348               data->expect_concatenated = 0;
00349 
00350               if (filterparams) {
00351                      zval **tmpzval = NULL;
00352 
00353                      if (Z_TYPE_P(filterparams) == IS_ARRAY || Z_TYPE_P(filterparams) == IS_OBJECT) {
00354 
00355                             if (SUCCESS == zend_hash_find(HASH_OF(filterparams), "concatenated", sizeof("concatenated"), (void **) &tmpzval) ) {
00356                                    zval tmp, *tmp2;
00357 
00358                                    tmp = **tmpzval;
00359                                    zval_copy_ctor(&tmp);
00360                                    tmp2 = &tmp;
00361                                    convert_to_boolean_ex(&tmp2);
00362                                    data->expect_concatenated = Z_LVAL(tmp);
00363                                    tmpzval = NULL;
00364                             }
00365 
00366                             zend_hash_find(HASH_OF(filterparams), "small", sizeof("small"), (void **) &tmpzval);
00367                      } else {
00368                             tmpzval = &filterparams;
00369                      }
00370 
00371                      if (tmpzval) {
00372                             zval tmp, *tmp2;
00373 
00374                             tmp = **tmpzval;
00375                             zval_copy_ctor(&tmp);
00376                             tmp2 = &tmp;
00377                             convert_to_boolean_ex(&tmp2);
00378                             data->small_footprint = Z_LVAL(tmp);
00379                      }
00380               }
00381 
00382               data->status = PHP_BZ2_UNITIALIZED;
00383               fops = &php_bz2_decompress_ops;
00384        } else if (strcasecmp(filtername, "bzip2.compress") == 0) {
00385               int blockSize100k = PHP_BZ2_FILTER_DEFAULT_BLOCKSIZE;
00386               int workFactor = PHP_BZ2_FILTER_DEFAULT_WORKFACTOR;
00387 
00388               if (filterparams) {
00389                      zval **tmpzval;
00390 
00391                      if (Z_TYPE_P(filterparams) == IS_ARRAY || Z_TYPE_P(filterparams) == IS_OBJECT) {
00392                             if (zend_hash_find(HASH_OF(filterparams), "blocks", sizeof("blocks"), (void**) &tmpzval) == SUCCESS) {
00393                                    /* How much memory to allocate (1 - 9) x 100kb */
00394                                    zval tmp;
00395        
00396                                    tmp = **tmpzval;
00397                                    zval_copy_ctor(&tmp);
00398                                    convert_to_long(&tmp);
00399                                    if (Z_LVAL(tmp) < 1 || Z_LVAL(tmp) > 9) {
00400                                           php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid parameter given for number of blocks to allocate. (%ld)", Z_LVAL_PP(tmpzval));
00401                                    } else {
00402                                           blockSize100k = Z_LVAL(tmp);
00403                                    }
00404                             }
00405 
00406                             if (zend_hash_find(HASH_OF(filterparams), "work", sizeof("work"), (void**) &tmpzval) == SUCCESS) {
00407                                    /* Work Factor (0 - 250) */
00408                                    zval tmp;
00409        
00410                                    tmp = **tmpzval;
00411                                    zval_copy_ctor(&tmp);
00412                                    convert_to_long(&tmp);
00413 
00414                                    if (Z_LVAL(tmp) < 0 || Z_LVAL(tmp) > 250) {
00415                                           php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid parameter given for work factor. (%ld)", Z_LVAL(tmp));
00416                                    } else {
00417                                           workFactor = Z_LVAL(tmp);
00418                                    }
00419                             }
00420                      }
00421               }
00422 
00423               status = BZ2_bzCompressInit(&(data->strm), blockSize100k, 0, workFactor);
00424               fops = &php_bz2_compress_ops;
00425        } else {
00426               status = BZ_DATA_ERROR;
00427        }
00428 
00429        if (status != BZ_OK) {
00430               /* Unspecified (probably strm) error, let stream-filter error do its own whining */
00431               pefree(data->strm.next_in, persistent);
00432               pefree(data->strm.next_out, persistent);
00433               pefree(data, persistent);
00434               return NULL;
00435        }
00436 
00437        return php_stream_filter_alloc(fops, data, persistent);
00438 }
00439 
00440 php_stream_filter_factory php_bz2_filter_factory = {
00441        php_bz2_filter_create
00442 };
00443 /* }}} */
00444 
00445 /*
00446  * Local variables:
00447  * tab-width: 4
00448  * c-basic-offset: 4
00449  * End:
00450  * vim600: sw=4 ts=4 fdm=marker
00451  * vim<600: sw=4 ts=4
00452  */