root/ext/bz2/bz2_filter.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. php_bz2_alloc
  2. php_bz2_free
  3. php_bz2_decompress_filter
  4. php_bz2_decompress_dtor
  5. php_bz2_compress_filter
  6. php_bz2_compress_dtor
  7. php_bz2_filter_create

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 7                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 The PHP Group                                |
   6    +----------------------------------------------------------------------+
   7    | This source file is subject to version 3.01 of the PHP license,      |
   8    | that is bundled with this package in the file LICENSE, and is        |
   9    | available through the world-wide-web at the following url:           |
  10    | http://www.php.net/license/3_01.txt                                  |
  11    | If you did not receive a copy of the PHP license and are unable to   |
  12    | obtain it through the world-wide-web, please send a note to          |
  13    | license@php.net so we can mail you a copy immediately.               |
  14    +----------------------------------------------------------------------+
  15    | Authors: Sara Golemon (pollita@php.net)                              |
  16    +----------------------------------------------------------------------+
  17 */
  18 
  19 /* $Id$ */
  20 
  21 #ifdef HAVE_CONFIG_H
  22 #include "config.h"
  23 #endif
  24 
  25 #include "php.h"
  26 #include "php_bz2.h"
  27 
  28 /* {{{ data structure */
  29 
  30 enum strm_status {
  31     PHP_BZ2_UNITIALIZED,
  32     PHP_BZ2_RUNNING,
  33     PHP_BZ2_FINISHED
  34 };
  35 
  36 typedef struct _php_bz2_filter_data {
  37         bz_stream strm;
  38         char *inbuf;
  39         char *outbuf;
  40         size_t inbuf_len;
  41         size_t outbuf_len;
  42 
  43         enum strm_status status;              /* Decompress option */
  44         unsigned int small_footprint : 1;     /* Decompress option */
  45         unsigned int expect_concatenated : 1; /* Decompress option */
  46 
  47         int persistent;
  48 } php_bz2_filter_data;
  49 
  50 /* }}} */
  51 
  52 /* {{{ Memory management wrappers */
  53 
  54 static void *php_bz2_alloc(void *opaque, int items, int size)
  55 {
  56         return (void *)safe_pemalloc(items, size, 0, ((php_bz2_filter_data*)opaque)->persistent);
  57 }
  58 
  59 static void php_bz2_free(void *opaque, void *address)
  60 {
  61         pefree((void *)address, ((php_bz2_filter_data*)opaque)->persistent);
  62 }
  63 /* }}} */
  64 
  65 /* {{{ bzip2.decompress filter implementation */
  66 
  67 static php_stream_filter_status_t php_bz2_decompress_filter(
  68         php_stream *stream,
  69         php_stream_filter *thisfilter,
  70         php_stream_bucket_brigade *buckets_in,
  71         php_stream_bucket_brigade *buckets_out,
  72         size_t *bytes_consumed,
  73         int flags
  74         )
  75 {
  76         php_bz2_filter_data *data;
  77         php_stream_bucket *bucket;
  78         size_t consumed = 0;
  79         int status;
  80         php_stream_filter_status_t exit_status = PSFS_FEED_ME;
  81         bz_stream *streamp;
  82 
  83         if (!Z_PTR(thisfilter->abstract)) {
  84                 /* Should never happen */
  85                 return PSFS_ERR_FATAL;
  86         }
  87 
  88         data = (php_bz2_filter_data *)Z_PTR(thisfilter->abstract);
  89         streamp = &(data->strm);
  90 
  91         while (buckets_in->head) {
  92                 size_t bin = 0, desired;
  93 
  94                 bucket = php_stream_bucket_make_writeable(buckets_in->head);
  95                 while (bin < bucket->buflen) {
  96                         if (data->status == PHP_BZ2_UNITIALIZED) {
  97                                 status = BZ2_bzDecompressInit(streamp, 0, data->small_footprint);
  98 
  99                                 if (BZ_OK != status) {
 100                                         php_stream_bucket_delref(bucket);
 101                                         return PSFS_ERR_FATAL;
 102                                 }
 103 
 104                                 data->status = PHP_BZ2_RUNNING;
 105                         }
 106 
 107                         if (data->status != PHP_BZ2_RUNNING) {
 108                                 consumed += bucket->buflen;
 109                                 break;
 110                         }
 111 
 112                         desired = bucket->buflen - bin;
 113                         if (desired > data->inbuf_len) {
 114                                 desired = data->inbuf_len;
 115                         }
 116                         memcpy(data->strm.next_in, bucket->buf + bin, desired);
 117                         data->strm.avail_in = desired;
 118 
 119                         status = BZ2_bzDecompress(&(data->strm));
 120 
 121                         if (status == BZ_STREAM_END) {
 122                                 BZ2_bzDecompressEnd(&(data->strm));
 123                                 if (data->expect_concatenated) {
 124                                         data->status = PHP_BZ2_UNITIALIZED;
 125                                 } else {
 126                                         data->status = PHP_BZ2_FINISHED;
 127                                 }
 128                         } else if (status != BZ_OK) {
 129                                 /* Something bad happened */
 130                                 php_stream_bucket_delref(bucket);
 131                                 return PSFS_ERR_FATAL;
 132                         }
 133                         desired -= data->strm.avail_in; /* desired becomes what we consumed this round through */
 134                         data->strm.next_in = data->inbuf;
 135                         data->strm.avail_in = 0;
 136                         consumed += desired;
 137                         bin += desired;
 138 
 139                         if (data->strm.avail_out < data->outbuf_len) {
 140                                 php_stream_bucket *out_bucket;
 141                                 size_t bucketlen = data->outbuf_len - data->strm.avail_out;
 142                                 out_bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0);
 143                                 php_stream_bucket_append(buckets_out, out_bucket);
 144                                 data->strm.avail_out = data->outbuf_len;
 145                                 data->strm.next_out = data->outbuf;
 146                                 exit_status = PSFS_PASS_ON;
 147                         } else if (status == BZ_STREAM_END && data->strm.avail_out >= data->outbuf_len) {
 148                                 /* no more data to decompress, and nothing was spat out */
 149                                 php_stream_bucket_delref(bucket);
 150                                 return PSFS_PASS_ON;
 151                         }
 152                 }
 153 
 154                 php_stream_bucket_delref(bucket);
 155         }
 156 
 157         if ((data->status == PHP_BZ2_RUNNING) && (flags & PSFS_FLAG_FLUSH_CLOSE)) {
 158                 /* Spit it out! */
 159                 status = BZ_OK;
 160                 while (status == BZ_OK) {
 161                         status = BZ2_bzDecompress(&(data->strm));
 162                         if (data->strm.avail_out < data->outbuf_len) {
 163                                 size_t bucketlen = data->outbuf_len - data->strm.avail_out;
 164 
 165                                 bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0);
 166                                 php_stream_bucket_append(buckets_out, bucket);
 167                                 data->strm.avail_out = data->outbuf_len;
 168                                 data->strm.next_out = data->outbuf;
 169                                 exit_status = PSFS_PASS_ON;
 170                         } else if (status == BZ_OK) {
 171                                 break;
 172                         }
 173                 }
 174         }
 175 
 176         if (bytes_consumed) {
 177                 *bytes_consumed = consumed;
 178         }
 179 
 180         return exit_status;
 181 }
 182 
 183 static void php_bz2_decompress_dtor(php_stream_filter *thisfilter)
 184 {
 185         if (thisfilter && Z_PTR(thisfilter->abstract)) {
 186                 php_bz2_filter_data *data = Z_PTR(thisfilter->abstract);
 187                 if (data->status == PHP_BZ2_RUNNING) {
 188                         BZ2_bzDecompressEnd(&(data->strm));
 189                 }
 190                 pefree(data->inbuf, data->persistent);
 191                 pefree(data->outbuf, data->persistent);
 192                 pefree(data, data->persistent);
 193         }
 194 }
 195 
 196 static php_stream_filter_ops php_bz2_decompress_ops = {
 197         php_bz2_decompress_filter,
 198         php_bz2_decompress_dtor,
 199         "bzip2.decompress"
 200 };
 201 /* }}} */
 202 
 203 /* {{{ bzip2.compress filter implementation */
 204 
 205 static php_stream_filter_status_t php_bz2_compress_filter(
 206         php_stream *stream,
 207         php_stream_filter *thisfilter,
 208         php_stream_bucket_brigade *buckets_in,
 209         php_stream_bucket_brigade *buckets_out,
 210         size_t *bytes_consumed,
 211         int flags
 212         )
 213 {
 214         php_bz2_filter_data *data;
 215         php_stream_bucket *bucket;
 216         size_t consumed = 0;
 217         int status;
 218         php_stream_filter_status_t exit_status = PSFS_FEED_ME;
 219 
 220         if (!Z_PTR(thisfilter->abstract)) {
 221                 /* Should never happen */
 222                 return PSFS_ERR_FATAL;
 223         }
 224 
 225         data = (php_bz2_filter_data *)Z_PTR(thisfilter->abstract);
 226 
 227         while (buckets_in->head) {
 228                 size_t bin = 0, desired;
 229 
 230                 bucket = php_stream_bucket_make_writeable(buckets_in->head);
 231 
 232                 while (bin < bucket->buflen) {
 233                         desired = bucket->buflen - bin;
 234                         if (desired > data->inbuf_len) {
 235                                 desired = data->inbuf_len;
 236                         }
 237                         memcpy(data->strm.next_in, bucket->buf + bin, desired);
 238                         data->strm.avail_in = desired;
 239 
 240                         status = BZ2_bzCompress(&(data->strm), flags & PSFS_FLAG_FLUSH_CLOSE ? BZ_FINISH : (flags & PSFS_FLAG_FLUSH_INC ? BZ_FLUSH : BZ_RUN));
 241                         if (status != BZ_RUN_OK && status != BZ_FLUSH_OK && status != BZ_FINISH_OK) {
 242                                 /* Something bad happened */
 243                                 php_stream_bucket_delref(bucket);
 244                                 return PSFS_ERR_FATAL;
 245                         }
 246                         desired -= data->strm.avail_in; /* desired becomes what we consumed this round through */
 247                         data->strm.next_in = data->inbuf;
 248                         data->strm.avail_in = 0;
 249                         consumed += desired;
 250                         bin += desired;
 251 
 252                         if (data->strm.avail_out < data->outbuf_len) {
 253                                 php_stream_bucket *out_bucket;
 254                                 size_t bucketlen = data->outbuf_len - data->strm.avail_out;
 255 
 256                                 out_bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0);
 257                                 php_stream_bucket_append(buckets_out, out_bucket);
 258                                 data->strm.avail_out = data->outbuf_len;
 259                                 data->strm.next_out = data->outbuf;
 260                                 exit_status = PSFS_PASS_ON;
 261                         }
 262                 }
 263                 php_stream_bucket_delref(bucket);
 264         }
 265 
 266         if (flags & PSFS_FLAG_FLUSH_CLOSE) {
 267                 /* Spit it out! */
 268                 status = BZ_FINISH_OK;
 269                 while (status == BZ_FINISH_OK) {
 270                         status = BZ2_bzCompress(&(data->strm), BZ_FINISH);
 271                         if (data->strm.avail_out < data->outbuf_len) {
 272                                 size_t bucketlen = data->outbuf_len - data->strm.avail_out;
 273 
 274                                 bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0);
 275                                 php_stream_bucket_append(buckets_out, bucket);
 276                                 data->strm.avail_out = data->outbuf_len;
 277                                 data->strm.next_out = data->outbuf;
 278                                 exit_status = PSFS_PASS_ON;
 279                         }
 280                 }
 281         }
 282 
 283         if (bytes_consumed) {
 284                 *bytes_consumed = consumed;
 285         }
 286         return exit_status;
 287 }
 288 
 289 static void php_bz2_compress_dtor(php_stream_filter *thisfilter)
 290 {
 291         if (Z_PTR(thisfilter->abstract)) {
 292                 php_bz2_filter_data *data = Z_PTR(thisfilter->abstract);
 293                 BZ2_bzCompressEnd(&(data->strm));
 294                 pefree(data->inbuf, data->persistent);
 295                 pefree(data->outbuf, data->persistent);
 296                 pefree(data, data->persistent);
 297         }
 298 }
 299 
 300 static php_stream_filter_ops php_bz2_compress_ops = {
 301         php_bz2_compress_filter,
 302         php_bz2_compress_dtor,
 303         "bzip2.compress"
 304 };
 305 
 306 /* }}} */
 307 
 308 /* {{{ bzip2.* common factory */
 309 
 310 static php_stream_filter *php_bz2_filter_create(const char *filtername, zval *filterparams, int persistent)
 311 {
 312         php_stream_filter_ops *fops = NULL;
 313         php_bz2_filter_data *data;
 314         int status = BZ_OK;
 315 
 316         /* Create this filter */
 317         data = pecalloc(1, sizeof(php_bz2_filter_data), persistent);
 318         if (!data) {
 319                 php_error_docref(NULL, E_WARNING, "Failed allocating %zu bytes", sizeof(php_bz2_filter_data));
 320                 return NULL;
 321         }
 322 
 323         /* Circular reference */
 324         data->strm.opaque = (void *) data;
 325 
 326         data->strm.bzalloc = php_bz2_alloc;
 327         data->strm.bzfree = php_bz2_free;
 328         data->persistent = persistent;
 329         data->strm.avail_out = data->outbuf_len = data->inbuf_len = 2048;
 330         data->strm.next_in = data->inbuf = (char *) pemalloc(data->inbuf_len, persistent);
 331         if (!data->inbuf) {
 332                 php_error_docref(NULL, E_WARNING, "Failed allocating %zu bytes", data->inbuf_len);
 333                 pefree(data, persistent);
 334                 return NULL;
 335         }
 336         data->strm.avail_in = 0;
 337         data->strm.next_out = data->outbuf = (char *) pemalloc(data->outbuf_len, persistent);
 338         if (!data->outbuf) {
 339                 php_error_docref(NULL, E_WARNING, "Failed allocating %zu bytes", data->outbuf_len);
 340                 pefree(data->inbuf, persistent);
 341                 pefree(data, persistent);
 342                 return NULL;
 343         }
 344 
 345         if (strcasecmp(filtername, "bzip2.decompress") == 0) {
 346                 data->small_footprint = 0;
 347                 data->expect_concatenated = 0;
 348 
 349                 if (filterparams) {
 350                         zval *tmpzval = NULL;
 351 
 352                         if (Z_TYPE_P(filterparams) == IS_ARRAY || Z_TYPE_P(filterparams) == IS_OBJECT) {
 353                                 if ((tmpzval = zend_hash_str_find(HASH_OF(filterparams), "concatenated", sizeof("concatenated")-1))) {
 354                                         data->expect_concatenated = zend_is_true(tmpzval);
 355                                         tmpzval = NULL;
 356                                 }
 357 
 358                                 tmpzval = zend_hash_str_find(HASH_OF(filterparams), "small", sizeof("small")-1);
 359                         } else {
 360                                 tmpzval = filterparams;
 361                         }
 362 
 363                         if (tmpzval) {
 364                                 data->small_footprint = zend_is_true(tmpzval);
 365                         }
 366                 }
 367 
 368                 data->status = PHP_BZ2_UNITIALIZED;
 369                 fops = &php_bz2_decompress_ops;
 370         } else if (strcasecmp(filtername, "bzip2.compress") == 0) {
 371                 int blockSize100k = PHP_BZ2_FILTER_DEFAULT_BLOCKSIZE;
 372                 int workFactor = PHP_BZ2_FILTER_DEFAULT_WORKFACTOR;
 373 
 374                 if (filterparams) {
 375                         zval *tmpzval;
 376 
 377                         if (Z_TYPE_P(filterparams) == IS_ARRAY || Z_TYPE_P(filterparams) == IS_OBJECT) {
 378                                 if ((tmpzval = zend_hash_str_find(HASH_OF(filterparams), "blocks", sizeof("blocks")-1))) {
 379                                         /* How much memory to allocate (1 - 9) x 100kb */
 380                                         zend_long blocks = zval_get_long(tmpzval);
 381                                         if (blocks < 1 || blocks > 9) {
 382                                                 php_error_docref(NULL, E_WARNING, "Invalid parameter given for number of blocks to allocate. (%pd)", blocks);
 383                                         } else {
 384                                                 blockSize100k = (int) blocks;
 385                                         }
 386                                 }
 387 
 388                                 if ((tmpzval = zend_hash_str_find(HASH_OF(filterparams), "work", sizeof("work")-1))) {
 389                                         /* Work Factor (0 - 250) */
 390                                         zend_long work = zval_get_long(tmpzval);
 391                                         if (work < 0 || work > 250) {
 392                                                 php_error_docref(NULL, E_WARNING, "Invalid parameter given for work factor. (%pd)", work);
 393                                         } else {
 394                                                 workFactor = (int) work;
 395                                         }
 396                                 }
 397                         }
 398                 }
 399 
 400                 status = BZ2_bzCompressInit(&(data->strm), blockSize100k, 0, workFactor);
 401                 fops = &php_bz2_compress_ops;
 402         } else {
 403                 status = BZ_DATA_ERROR;
 404         }
 405 
 406         if (status != BZ_OK) {
 407                 /* Unspecified (probably strm) error, let stream-filter error do its own whining */
 408                 pefree(data->strm.next_in, persistent);
 409                 pefree(data->strm.next_out, persistent);
 410                 pefree(data, persistent);
 411                 return NULL;
 412         }
 413 
 414         return php_stream_filter_alloc(fops, data, persistent);
 415 }
 416 
 417 php_stream_filter_factory php_bz2_filter_factory = {
 418         php_bz2_filter_create
 419 };
 420 /* }}} */
 421 
 422 /*
 423  * Local variables:
 424  * tab-width: 4
 425  * c-basic-offset: 4
 426  * End:
 427  * vim600: sw=4 ts=4 fdm=marker
 428  * vim<600: sw=4 ts=4
 429  */

/* [<][>][^][v][top][bottom][index][help] */