Annotation of embedaddon/php/ext/bz2/bz2_filter.c, revision 1.1.1.3

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
1.1.1.3 ! misho       5:    | Copyright (c) 1997-2013 The PHP Group                                |
1.1       misho       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: 
1.1.1.2   misho      19: /* $Id$ */
1.1       misho      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:        int persistent;
                     38:        bz_stream strm;
                     39:        char *inbuf;
                     40:        size_t inbuf_len;
                     41:        char *outbuf;
                     42:        size_t outbuf_len;
                     43:        
                     44:        /* Decompress options */
                     45:        enum strm_status status;
                     46:        unsigned int small_footprint : 1;
                     47:        unsigned int expect_concatenated : 1;
                     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:        TSRMLS_DC)
                     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 (!thisfilter || !thisfilter->abstract) {
                     84:                /* Should never happen */
                     85:                return PSFS_ERR_FATAL;
                     86:        }
                     87: 
                     88:        data = (php_bz2_filter_data *)(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 TSRMLS_CC);
                     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:                                        return PSFS_ERR_FATAL;
                    101:                                }
                    102: 
                    103:                                data->status = PHP_BZ2_RUNNING;
                    104:                        }
                    105: 
                    106:                        if (data->status != PHP_BZ2_RUNNING) {
                    107:                                consumed += bucket->buflen;
                    108:                                break;
                    109:                        }
                    110: 
                    111:                        desired = bucket->buflen - bin;
                    112:                        if (desired > data->inbuf_len) {
                    113:                                desired = data->inbuf_len;
                    114:                        }
                    115:                        memcpy(data->strm.next_in, bucket->buf + bin, desired);
                    116:                        data->strm.avail_in = desired;
                    117: 
                    118:                        status = BZ2_bzDecompress(&(data->strm));
                    119: 
                    120:                        if (status == BZ_STREAM_END) {
                    121:                                BZ2_bzDecompressEnd(&(data->strm));
                    122:                                if (data->expect_concatenated) {
                    123:                                        data->status = PHP_BZ2_UNITIALIZED;
                    124:                                } else {
                    125:                                        data->status = PHP_BZ2_FINISHED;
                    126:                                }
                    127:                        } else if (status != BZ_OK) {
                    128:                                /* Something bad happened */
                    129:                                php_stream_bucket_delref(bucket TSRMLS_CC);
                    130:                                return PSFS_ERR_FATAL;
                    131:                        }
                    132:                        desired -= data->strm.avail_in; /* desired becomes what we consumed this round through */
                    133:                        data->strm.next_in = data->inbuf;
                    134:                        data->strm.avail_in = 0;
                    135:                        consumed += desired;
                    136:                        bin += desired;
                    137: 
                    138:                        if (data->strm.avail_out < data->outbuf_len) {
                    139:                                php_stream_bucket *out_bucket;
                    140:                                size_t bucketlen = data->outbuf_len - data->strm.avail_out;
                    141:                                out_bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0 TSRMLS_CC);
                    142:                                php_stream_bucket_append(buckets_out, out_bucket TSRMLS_CC);
                    143:                                data->strm.avail_out = data->outbuf_len;
                    144:                                data->strm.next_out = data->outbuf;
                    145:                                exit_status = PSFS_PASS_ON;
                    146:                        } else if (status == BZ_STREAM_END && data->strm.avail_out >= data->outbuf_len) {
                    147:                                /* no more data to decompress, and nothing was spat out */
                    148:                                php_stream_bucket_delref(bucket TSRMLS_CC);
                    149:                                return PSFS_PASS_ON;
                    150:                        }
                    151:                }
                    152: 
                    153:                php_stream_bucket_delref(bucket TSRMLS_CC);
                    154:        }
                    155: 
                    156:        if ((data->status == PHP_BZ2_RUNNING) && (flags & PSFS_FLAG_FLUSH_CLOSE)) {
                    157:                /* Spit it out! */
                    158:                status = BZ_OK;
                    159:                while (status == BZ_OK) {
                    160:                        status = BZ2_bzDecompress(&(data->strm));
                    161:                        if (data->strm.avail_out < data->outbuf_len) {
                    162:                                size_t bucketlen = data->outbuf_len - data->strm.avail_out;
                    163: 
                    164:                                bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0 TSRMLS_CC);
                    165:                                php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
                    166:                                data->strm.avail_out = data->outbuf_len;
                    167:                                data->strm.next_out = data->outbuf;
                    168:                                exit_status = PSFS_PASS_ON;
                    169:                        } else if (status == BZ_OK) {
                    170:                                break;
                    171:                        }
                    172:                }
                    173:        }
                    174: 
                    175:        if (bytes_consumed) {
                    176:                *bytes_consumed = consumed;
                    177:        }
                    178: 
                    179:        return exit_status;
                    180: }
                    181: 
                    182: static void php_bz2_decompress_dtor(php_stream_filter *thisfilter TSRMLS_DC)
                    183: {
                    184:        if (thisfilter && thisfilter->abstract) {
                    185:                php_bz2_filter_data *data = thisfilter->abstract;
                    186:                if (data->status == PHP_BZ2_RUNNING) {
                    187:                        BZ2_bzDecompressEnd(&(data->strm));
                    188:                }
                    189:                pefree(data->inbuf, data->persistent);
                    190:                pefree(data->outbuf, data->persistent);
                    191:                pefree(data, data->persistent);
                    192:        }
                    193: }
                    194: 
                    195: static php_stream_filter_ops php_bz2_decompress_ops = {
                    196:        php_bz2_decompress_filter,
                    197:        php_bz2_decompress_dtor,
                    198:        "bzip2.decompress"
                    199: };
                    200: /* }}} */
                    201: 
                    202: /* {{{ bzip2.compress filter implementation */
                    203: 
                    204: static php_stream_filter_status_t php_bz2_compress_filter(
                    205:        php_stream *stream,
                    206:        php_stream_filter *thisfilter,
                    207:        php_stream_bucket_brigade *buckets_in,
                    208:        php_stream_bucket_brigade *buckets_out,
                    209:        size_t *bytes_consumed,
                    210:        int flags
                    211:        TSRMLS_DC)
                    212: {
                    213:        php_bz2_filter_data *data;
                    214:        php_stream_bucket *bucket;
                    215:        size_t consumed = 0;
                    216:        int status;
                    217:        php_stream_filter_status_t exit_status = PSFS_FEED_ME;
                    218:        bz_stream *streamp;
                    219: 
                    220:        if (!thisfilter || !thisfilter->abstract) {
                    221:                /* Should never happen */
                    222:                return PSFS_ERR_FATAL;
                    223:        }
                    224: 
                    225:        data = (php_bz2_filter_data *)(thisfilter->abstract);
                    226:        streamp = &(data->strm);
                    227: 
                    228:        while (buckets_in->head) {
                    229:                size_t bin = 0, desired;
                    230: 
                    231:                bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC);
                    232: 
                    233:                while (bin < bucket->buflen) {
                    234:                        desired = bucket->buflen - bin;
                    235:                        if (desired > data->inbuf_len) {
                    236:                                desired = data->inbuf_len;
                    237:                        }
                    238:                        memcpy(data->strm.next_in, bucket->buf + bin, desired);
                    239:                        data->strm.avail_in = desired;
                    240: 
                    241:                        status = BZ2_bzCompress(&(data->strm), flags & PSFS_FLAG_FLUSH_CLOSE ? BZ_FINISH : (flags & PSFS_FLAG_FLUSH_INC ? BZ_FLUSH : BZ_RUN));
                    242:                        if (status != BZ_RUN_OK && status != BZ_FLUSH_OK && status != BZ_FINISH_OK) {
                    243:                                /* Something bad happened */
                    244:                                php_stream_bucket_delref(bucket TSRMLS_CC);
                    245:                                return PSFS_ERR_FATAL;
                    246:                        }
                    247:                        desired -= data->strm.avail_in; /* desired becomes what we consumed this round through */
                    248:                        data->strm.next_in = data->inbuf;
                    249:                        data->strm.avail_in = 0;
                    250:                        consumed += desired;
                    251:                        bin += desired;
                    252: 
                    253:                        if (data->strm.avail_out < data->outbuf_len) {
                    254:                                php_stream_bucket *out_bucket;
                    255:                                size_t bucketlen = data->outbuf_len - data->strm.avail_out;
                    256: 
                    257:                                out_bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0 TSRMLS_CC);
                    258:                                php_stream_bucket_append(buckets_out, out_bucket TSRMLS_CC);
                    259:                                data->strm.avail_out = data->outbuf_len;
                    260:                                data->strm.next_out = data->outbuf;
                    261:                                exit_status = PSFS_PASS_ON;
                    262:                        }
                    263:                }
                    264:                php_stream_bucket_delref(bucket TSRMLS_CC);
                    265:        }
                    266: 
                    267:        if (flags & PSFS_FLAG_FLUSH_CLOSE) {
                    268:                /* Spit it out! */
                    269:                status = BZ_FINISH_OK;
                    270:                while (status == BZ_FINISH_OK) {
                    271:                        status = BZ2_bzCompress(&(data->strm), BZ_FINISH);
                    272:                        if (data->strm.avail_out < data->outbuf_len) {
                    273:                                size_t bucketlen = data->outbuf_len - data->strm.avail_out;
                    274: 
                    275:                                bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0 TSRMLS_CC);
                    276:                                php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
                    277:                                data->strm.avail_out = data->outbuf_len;
                    278:                                data->strm.next_out = data->outbuf;
                    279:                                exit_status = PSFS_PASS_ON;
                    280:                        }
                    281:                }
                    282:        }
                    283: 
                    284:        if (bytes_consumed) {
                    285:                *bytes_consumed = consumed;
                    286:        }
                    287:        return exit_status;
                    288: }
                    289: 
                    290: static void php_bz2_compress_dtor(php_stream_filter *thisfilter TSRMLS_DC)
                    291: {
                    292:        if (thisfilter && thisfilter->abstract) {
                    293:                php_bz2_filter_data *data = thisfilter->abstract;
                    294:                BZ2_bzCompressEnd(&(data->strm));
                    295:                pefree(data->inbuf, data->persistent);
                    296:                pefree(data->outbuf, data->persistent);
                    297:                pefree(data, data->persistent);
                    298:        }
                    299: }
                    300: 
                    301: static php_stream_filter_ops php_bz2_compress_ops = {
                    302:        php_bz2_compress_filter,
                    303:        php_bz2_compress_dtor,
                    304:        "bzip2.compress"
                    305: };
                    306: 
                    307: /* }}} */
                    308: 
                    309: /* {{{ bzip2.* common factory */
                    310: 
                    311: static php_stream_filter *php_bz2_filter_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
                    312: {
                    313:        php_stream_filter_ops *fops = NULL;
                    314:        php_bz2_filter_data *data;
                    315:        int status = BZ_OK;
                    316: 
                    317:        /* Create this filter */
                    318:        data = pecalloc(1, sizeof(php_bz2_filter_data), persistent);
                    319:        if (!data) {
                    320:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %zu bytes", sizeof(php_bz2_filter_data));
                    321:                return NULL;
                    322:        }
                    323: 
                    324:        /* Circular reference */
                    325:        data->strm.opaque = (void *) data;
                    326: 
                    327:        data->strm.bzalloc = php_bz2_alloc;
                    328:        data->strm.bzfree = php_bz2_free;
                    329:        data->persistent = persistent;
                    330:        data->strm.avail_out = data->outbuf_len = data->inbuf_len = 2048;
                    331:        data->strm.next_in = data->inbuf = (char *) pemalloc(data->inbuf_len, persistent);
                    332:        if (!data->inbuf) {
                    333:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %zu bytes", data->inbuf_len);
                    334:                pefree(data, persistent);
                    335:                return NULL;
                    336:        }
                    337:        data->strm.avail_in = 0;
                    338:        data->strm.next_out = data->outbuf = (char *) pemalloc(data->outbuf_len, persistent);
                    339:        if (!data->outbuf) {
                    340:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %zu bytes", data->outbuf_len);
                    341:                pefree(data->inbuf, persistent);
                    342:                pefree(data, persistent);
                    343:                return NULL;
                    344:        }
                    345: 
                    346:        if (strcasecmp(filtername, "bzip2.decompress") == 0) {
                    347:                data->small_footprint = 0;
                    348:                data->expect_concatenated = 0;
                    349: 
                    350:                if (filterparams) {
                    351:                        zval **tmpzval = NULL;
                    352: 
                    353:                        if (Z_TYPE_P(filterparams) == IS_ARRAY || Z_TYPE_P(filterparams) == IS_OBJECT) {
                    354: 
                    355:                                if (SUCCESS == zend_hash_find(HASH_OF(filterparams), "concatenated", sizeof("concatenated"), (void **) &tmpzval) ) {
                    356:                                        zval tmp, *tmp2;
                    357: 
                    358:                                        tmp = **tmpzval;
                    359:                                        zval_copy_ctor(&tmp);
                    360:                                        tmp2 = &tmp;
                    361:                                        convert_to_boolean_ex(&tmp2);
                    362:                                        data->expect_concatenated = Z_LVAL(tmp);
                    363:                                        tmpzval = NULL;
                    364:                                }
                    365: 
                    366:                                zend_hash_find(HASH_OF(filterparams), "small", sizeof("small"), (void **) &tmpzval);
                    367:                        } else {
                    368:                                tmpzval = &filterparams;
                    369:                        }
                    370: 
                    371:                        if (tmpzval) {
                    372:                                zval tmp, *tmp2;
                    373: 
                    374:                                tmp = **tmpzval;
                    375:                                zval_copy_ctor(&tmp);
                    376:                                tmp2 = &tmp;
                    377:                                convert_to_boolean_ex(&tmp2);
                    378:                                data->small_footprint = Z_LVAL(tmp);
                    379:                        }
                    380:                }
                    381: 
                    382:                data->status = PHP_BZ2_UNITIALIZED;
                    383:                fops = &php_bz2_decompress_ops;
                    384:        } else if (strcasecmp(filtername, "bzip2.compress") == 0) {
                    385:                int blockSize100k = PHP_BZ2_FILTER_DEFAULT_BLOCKSIZE;
                    386:                int workFactor = PHP_BZ2_FILTER_DEFAULT_WORKFACTOR;
                    387: 
                    388:                if (filterparams) {
                    389:                        zval **tmpzval;
                    390: 
                    391:                        if (Z_TYPE_P(filterparams) == IS_ARRAY || Z_TYPE_P(filterparams) == IS_OBJECT) {
                    392:                                if (zend_hash_find(HASH_OF(filterparams), "blocks", sizeof("blocks"), (void**) &tmpzval) == SUCCESS) {
                    393:                                        /* How much memory to allocate (1 - 9) x 100kb */
                    394:                                        zval tmp;
                    395:        
                    396:                                        tmp = **tmpzval;
                    397:                                        zval_copy_ctor(&tmp);
                    398:                                        convert_to_long(&tmp);
                    399:                                        if (Z_LVAL(tmp) < 1 || Z_LVAL(tmp) > 9) {
                    400:                                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid parameter given for number of blocks to allocate. (%ld)", Z_LVAL_PP(tmpzval));
                    401:                                        } else {
                    402:                                                blockSize100k = Z_LVAL(tmp);
                    403:                                        }
                    404:                                }
                    405: 
                    406:                                if (zend_hash_find(HASH_OF(filterparams), "work", sizeof("work"), (void**) &tmpzval) == SUCCESS) {
                    407:                                        /* Work Factor (0 - 250) */
                    408:                                        zval tmp;
                    409:        
                    410:                                        tmp = **tmpzval;
                    411:                                        zval_copy_ctor(&tmp);
                    412:                                        convert_to_long(&tmp);
                    413: 
                    414:                                        if (Z_LVAL(tmp) < 0 || Z_LVAL(tmp) > 250) {
                    415:                                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid parameter given for work factor. (%ld)", Z_LVAL(tmp));
                    416:                                        } else {
                    417:                                                workFactor = Z_LVAL(tmp);
                    418:                                        }
                    419:                                }
                    420:                        }
                    421:                }
                    422: 
                    423:                status = BZ2_bzCompressInit(&(data->strm), blockSize100k, 0, workFactor);
                    424:                fops = &php_bz2_compress_ops;
                    425:        } else {
                    426:                status = BZ_DATA_ERROR;
                    427:        }
                    428: 
                    429:        if (status != BZ_OK) {
                    430:                /* Unspecified (probably strm) error, let stream-filter error do its own whining */
                    431:                pefree(data->strm.next_in, persistent);
                    432:                pefree(data->strm.next_out, persistent);
                    433:                pefree(data, persistent);
                    434:                return NULL;
                    435:        }
                    436: 
                    437:        return php_stream_filter_alloc(fops, data, persistent);
                    438: }
                    439: 
                    440: php_stream_filter_factory php_bz2_filter_factory = {
                    441:        php_bz2_filter_create
                    442: };
                    443: /* }}} */
                    444: 
                    445: /*
                    446:  * Local variables:
                    447:  * tab-width: 4
                    448:  * c-basic-offset: 4
                    449:  * End:
                    450:  * vim600: sw=4 ts=4 fdm=marker
                    451:  * vim<600: sw=4 ts=4
                    452:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>